After executing these lines in Perl:
my $data = `curl '$url'`;
my $pets = XMLin($data)->(pets);
I have an array reference that contains references to hashes:
$VAR1 = [
{
'title' => 'cat',
'count' => '210'
},
{
'title' => 'dog',
'count' => '210'
}
]
In Perl, how do I sort the hashes first by count and secondarily by title. Then print to STDOUT the count followed by the title on each newline.
Assuming you want counts in descending order and titles ascending:
That’s compact code written in a functional style. To help understand it, let’s look at equivalent code in a more familiar, imperative style.
Perl’s
sortoperator takes an optional SUBNAME parameter that allows you to factor out your comparison and give it a name that describes what it does. When I do this, I like to begin the sub’s name withby_to makesort by_...ready more naturally.To start, you might have written
Note that no comma follows the SUBNAME in this form!
To address another commenter’s question, you could use
orrather than||inby_count_then_titleif you find it more readable. Both<=>andcmphave higher precedence (which you might think of as binding more tightly) than||andor, so it’s strictly a matter of style.To print the sorted array, a more familiar choice might be
Perl uses
$_if you don’t specify the variable that gets each value, so the following has the same meaning:The
forandforeachkeywords are synonyms, but I find that the uses above, i.e.,foreachif I’m going to name a variable orforotherwise, read most naturally.Using
map, a close cousin offoreach, instead isn’t much different:You could also promote
printthrough themap:Finally, to avoid repetition of
$_->{...}, the hash slice@$_{"count", "title"}gives us the values associated with count and title in the loop’s current record. Having the values, we need to join them with a single space and append a newline to the result, soRemember that
qw//is shorthand for writing a list of strings. As this example shows, read amapexpression back-to-front (or bottom-to-top the way I indented it): first sort the records, then format them, then print them.You could eliminate the temporary
@sortedbut call the named comparison:If the application of
joinis just too verbose for your taste, then