I have a data structure which looks like this (hash of hashes):
$VAR1 = {
'masterkeyB' => {
'D' => ['b', 'c', 'a'],
'A' => ['b', 'a', 'c'],
'C' => ['a', 'c', 'b'],
'B' => ['a', 'c', 'b'],
},
'masterkeyA' => {
'B' => ['a', 'c', 'b'],
'C' => ['a', 'c', 'b'],
'A' => ['b', 'a', 'c'],
'D' => ['b', 'c', 'a'],
}
};
I would like to sort this structure in alphabetical order :
$VAR1 = {
'masterkeyA' => {
'A' => ['a', 'b', 'c'],
'B' => ['a', 'b', 'c'],
'C' => ['a', 'c', 'b'],
'D' => ['a', 'b', 'c'],
},
'masterkeyB' => {
'A' => ['a', 'b', 'c'],
'B' => ['a', 'b', 'c'],
'C' => ['a', 'c', 'b'],
'D' => ['a', 'b', 'c'],
}
};
Note that all the arrays are sorted except for 'C'.
Just iterate over the keys in nested loops, sort the values as you encounter them. Edit: see http://p3rl.org/dsc#HASHES-OF-HASHES
use feature qw(postderef);
use Tie::Hash::Indexed qw();
my $unsorted = {
'masterkeyB' => {
'D' => ['b', 'c', 'a'],
'A' => ['b', 'a', 'c'],
'C' => ['a', 'c', 'b'],
'B' => ['a', 'c', 'b'],
},
'masterkeyA' => {
'B' => ['a', 'c', 'b'],
'C' => ['a', 'c', 'b'],
'A' => ['b', 'a', 'c'],
'D' => ['b', 'c', 'a'],
}
};
tie my %sorted, 'Tie::Hash::Indexed';
for my $k1 (sort keys $unsorted->%*) {
for my $k2 (sort keys $unsorted->{$k1}->%*) {
my $v = $unsorted->{$k1}{$k2};
$v = [sort $v->@*] unless 'C' eq $k2;
$sorted{$k1}{$k2} = $v;
}
}
__END__
$HASH1 = {
masterkeyA => {
A => ['a', 'b', 'c'],
B => ['a', 'b', 'c'],
C => ['a', 'c', 'b'],
D => ['a', 'b', 'c']
},
masterkeyB => {
A => ['a', 'b', 'c'],
B => ['a', 'b', 'c'],
C => ['a', 'c', 'b'],
D => ['a', 'b', 'c']
}
};
Unlike arrays, hashes in perl don't stay in sorted order, so the common paradigm is to sort the hash keys while you're traversing the data structure. The basic code snippets you need are
for my $k ( sort keys %hash ) {
for my $sk ( sort keys %{$hash->{$k}} ) {
# do something
}
}
to access hash keys in sorted order, and
if ( $k ne 'KEY' ) {
# sort this array
$hash->{$k} = sort @{$hash->{$k}}
}
to selectively sort arrays.
For example, say you're printing out the hash:
use strict;
use warnings;
use feature ':5.16';
my $data = {
'masterkeyB' => {
'D' => ['b', 'c', 'a'],
'A' => ['b', 'a', 'c'],
'C' => ['a', 'c', 'b'],
'B' => ['a', 'c', 'b'],
},
'masterkeyA' => {
'B' => ['a', 'c', 'b'],
'C' => ['a', 'c', 'b'],
'A' => ['b', 'a', 'c'],
'D' => ['b', 'c', 'a'],
}
};
for my $mk ( sort keys %$data ) {
say $mk;
for my $letter ( sort keys %{$data->{$mk}} ) {
say ' ' . $letter;
if ( $letter eq 'C') {
say ' [ ' . join(", ", @{$data->{$mk}{$letter}}) . ' ]';
}
else {
say ' [ ' . join(", ", sort @{$data->{$mk}{$letter}}) . ' ]';
}
}
}
result:
masterkeyA
A
[ a, b, c ]
B
[ a, b, c ]
C
[ a, c, b ]
D
[ a, b, c ]
masterkeyB
A
[ a, b, c ]
B
[ a, b, c ]
C
[ a, c, b ]
D
[ a, b, c ]
Obviously you can change the say
lines to do whatever you are planning to do with this data.
I think this does what you need. Not easy to ready but works.
my %sorted;
map {my $key = $_; map {$sorted{$key}->{$_} = ($_ eq 'C' ? $hash{$key}->{$_} : [sort @{$hash{$key}->{$_}}])} keys %{$hash{$key}}} keys %hash;
or sort original hash
map {my $key = $_; map {$hash{$key}->{$_} = ($_ eq 'C' ? $hash{$key}->{$_} : [sort @{$hash{$key}->{$_}}])} keys %{$hash{$key}}} keys %hash;
or shorter version
map {my $key = $_; map {$hash{$key}->{$_} = [sort @{$hash{$key}->{$_}}] if($_ ne 'C')} keys %{$hash{$key}}} keys %hash;
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.