Reputation: 13
I am experimenting with a nested data structures in Perl these days. Let's say I have hash of array of hashes and I'd like to get values sorted by keys alphabetically. How do I do it?
The code:
#!/usr/bin/perl
use JSON::XS;
use Data::Dumper;
#use diagnostics;
use warnings;
my $school_data = {'School' => '156', 'Pupils' => [{'Person' => {name => 'Alice', age => 10, pet => 'cat'},'id' => 56},{'Person' => {name => 'John', age => 9, pet => 'dog'},id => 4}]};
print "\$school_data:" . Dumper ($school_data);
my $ref = $school_data->{Pupils};
foreach $pupil (@$ref){
my @temp = sort (values $pupil->{'Person'});
print "\n@temp\n";
}
Gives me an output:
$school_data: $VAR1 = {
'School' => '156',
'Pupils' => [
{
'id' => 56,
'Person' => {
'pet' => 'cat',
'name' => 'Alice',
'age' => 10
}
},
{
'Person' => {
'age' => 9,
'name' => 'John',
'pet' => 'dog'
},
'id' => 4
}
]
};
10 Alice cat
9 John dog
And I wish to get values sorted by keys alphabetically (pet name age):
cat Alice 10
dog John 9
Looking forward to your help. Thank you.
Upvotes: 1
Views: 551
Reputation: 53478
Hashes as I'm sure you know, don't store any sort of ordering, just key and value mappings.
But the sort
function can take pretty much arbitrary code, that returns position dependant negative/0/positive to define sort order.
But you need to sort your 'top level' based on a subkey.
If you need to output values in a particular order - remember hashes are unordered you can use a slice.
So:
#!/usr/bin/env perl
use JSON::XS;
use Data::Dumper;
#use diagnostics;
use strict;
use warnings;
my @things = qw ( pet name age );
my $school_data = {
'School' => '156',
'Pupils' => [
{ 'Person' => { name => 'Alice', age => 10, pet => 'cat' },
'id' => 56
},
{ 'Person' => { name => 'John', age => 9, pet => 'dog' }, id => 4 }
]
};
print "\$school_data:" . Dumper( $school_data->{Pupils} );
foreach my $pupil ( sort { $_ -> {Person} -> {name}
cmp $_ -> {Person} -> {name} }
@{ $school_data->{Pupils} } )
{
print join " ", @{$pupil->{Person}}{@things}, "\n";
}
For multi-key sort, sort works just fine - provided the thing it returns is a numeric value.
So you could:
sort { $_ -> {Person} -> {name} cmp $_ -> {Person} -> {name}
|| $_ -> {Person} -> {age} <=> $_ -> {Person} -> {age}
|| $_ -> {Person} -> {pet} <=> $_ -> {Person} -> {pet} }
Upvotes: 2