Perl - Hash of hash and columns :(
I've a set of strings with variable sizes, for example:
AAA23
AB1D1
A1BC
AAB212
My goal is have in alphabetical order and unique characters collected for COLUMNS, such as:
first column : AAAA
sec开发者_如何学JAVAond column : AB1A
and so on...
For this moment I was able to extract the posts through a hash of hashes. But now, how can I sort data? Could I for each hash of hash make a new array?
Thank you very much for you help!
Al
My code:
#!/usr/bin/perl
use strict;
use warnings;
my @sessions = (
"AAAA",
"AAAC",
"ABAB",
"ABAD"
);
my $length_max = 0;
my $length_tmp = 0;
my %columns;
foreach my $string (@sessions){
my $l = length($string);
if ($l > $length_tmp){
$length_max = $l;
}
}
print "max legth : $length_max\n\n";
my $n = 1;
foreach my $string (@sessions){
my @ch = split("",$string);
for my $col (1..$length_max){
$columns{$n}{$col} = $ch[$col-1];
}
$n++;
}
foreach my $col (keys %columns) {
print "colonna : $col\n";
my $deref = $columns{$col};
foreach my $pos (keys %$deref){
print " posizione : $pos --> $$deref{$pos}\n";
}
print "\n";
}
exit(0);
What you're doing is rotating the array. It doesn't need a hash of hash or anything, just another array. Surprisingly, neither List::Util nor List::MoreUtils supplies one. Here's a straightforward implementation with a test. I presumed you want short entries filled in with spaces so the columns come out correct.
#!/usr/bin/perl
use strict;
use warnings;
use Test::More;
use List::Util qw(max);
my @Things = qw(
AAA23
AB1D1
A1BC
AAB212
);
sub rotate {
my @rows = @_;
my $maxlength = max map { length $_ } @rows;
my @columns;
for my $row (@rows) {
my @chars = split //, $row;
for my $colnum (1..$maxlength) {
my $idx = $colnum - 1;
$columns[$idx] .= $chars[$idx] || ' ';
}
}
return @columns;
}
sub print_columns {
my @columns = @_;
for my $idx (0..$#columns) {
printf "Column %d: %s\n", $idx + 1, $columns[$idx];
}
}
sub test_rotate {
is_deeply [rotate @_], [
"AAAA",
"AB1A",
"A1BB",
"2DC2",
"31 1",
" 2",
];
}
test_rotate(@Things);
print_columns(@Things);
done_testing;
You can sort the output of %columns
in your code with
foreach my $i (sort { $a <=> $b } keys %columns) {
print join(" " => sort values %{ $columns{$i} }), "\n";
}
This gives
A A A A A A A C A A B B A A B D
But using index numbers as hash keys screams that you should use an array instead, so let's do that. To get the columns, use
sub columns {
my @strings = @_;
my @columns;
while (@strings) {
push @columns => [ sort map s/^(.)//s ? $1 : (), @strings ];
@strings = grep length, @strings;
}
@columns;
}
Given the strings from your question, it returns
A A A A 1 A A B 1 A B B 2 2 C D 1 1 3 2
As you can see, this is unsorted and repeats characters. With Perl, when you see the word unique, always think of hashes!
sub unique_sorted_columns {
map { my %unique;
++$unique{$_} for @$_;
[ sort keys %unique ];
}
columns @_;
}
If you don't mind destroying information, you can have columns
sort and filter duplicates:
sub columns {
my @strings = @_;
my @columns;
while (@strings) {
my %unique;
map { ++$unique{$1} if s/^(.)//s } @strings;
push @columns => [ sort keys %unique ];
@strings = grep length, @strings;
}
@columns;
}
Output:
A 1 A B 1 A B 2 C D 1 3 2
精彩评论