thillai_selvan has asked for the wisdom of the Perl Monks concerning the following question:

use strict; use warnings; my @aoh =( { 3 => 15, 4 => 8, 5 => 9, }, { 3 => 11, 4 => 25, 5 => 6, }, { 3 => 5, 4 => 18, 5 => 5, }, { 0 => 16, 1 => 11, 2 => 7, }, { 0 => 21, 1 => 13, 2 => 31, }, { 0 => 11, 1 => 14, 2 => 31, }, );
Here I want to sort the hash elements based on their values. So I want the output to be like this
@aoh =( { 4 => 8, 5 => 9, 3 => 15, }, { 5 => 6, 3 => 11, 4 => 25, }, { 5 => 5, 3 => 5, 4 => 18, }, { 2 => 7, 1 => 11, 0 => 16, }, { 1 => 13, 0 => 21, 2 => 31, }, { 0 => 11, 1 => 14, 2 => 31, }, );
How can I achieve this? Any help much appreciated...

Replies are listed 'Best First'.
Re: Array of hash sorting problem
by Corion (Patriarch) on Mar 25, 2010 at 09:50 UTC

    This is a FAQ. Typing perldoc -q sort or looking at perlfaq4 tells you the answer.

      I know this. I know about sort. I am facing the problem in dereferencing the array. Can you please explain the clear way.

        You don't need to dereference the array, because the array elements to compare will be stored in $a and $b. All you need to do is to extract the fields of your array elements and compare them. See, again, the examples in perlfaq4, and also maybe References Quick Reference. Maybe you want to show the code you have written and explain where you actually have the problems instead of trying to make us write your code for you.

        Each element in the array is a reference to an anon hash. Loop over these references, then deference to get the keys to put into sort. output of sort is sorted keys. see below.
        use strict; use warnings; my @aoh =( { 3 => 15, 4 => 8, 5 => 9, }, { 3 => 11, 4 => 25, 5 => 6, }, { 3 => 5, 4 => 18, 5 => 5, }, { 0 => 16, 1 => 11, 2 => 7, }, { 0 => 21, 1 => 13, 2 => 31, }, { 0 => 11, 1 => 14, 2 => 31, }, ); foreach my $href (@aoh) { my @sorted_keys = sort {$href->{$a} <=> $href->{$b} } keys %$href; foreach my $key (@sorted_keys) { print "$key => $href->{$key}\n" } print "\n"; } __END__ 4 => 8 5 => 9 3 => 15 5 => 6 3 => 11 4 => 25 3 => 5 5 => 5 4 => 18 2 => 7 1 => 11 0 => 16 1 => 13 0 => 21 2 => 31 0 => 11 1 => 14 2 => 31
Re: Array of hash sorting problem
by moritz (Cardinal) on Mar 25, 2010 at 10:32 UTC

    I hope you are aware that hashes are not sorted, so as Perl data structures the following two are exactly equivalent:

    { 3 => 15, 4 => 8, 5 => 9, } # and { 4 => 8, 5 => 9, 3 => 15, }

    So you can either sort and print, or sort and store in a different data structure - sorting and trying to store it in a another array of hashes doesn't make sense.

    Perl 6 - links to (nearly) everything that is Perl 6.

      Finally, a voice of reason.

      To the rest of you, keep trying to sort those hashes.

        You should really read the FAQ, because yes, you can sort hashes "7stud"
Re: Array of hash sorting problem
by almut (Canon) on Mar 25, 2010 at 10:11 UTC
    #!/usr/bin/perl -l use strict; use warnings; my @aoh =( { 3 => 15, 4 => 8, 5 => 9, }, { 3 => 11, 4 => 25, 5 => 6, }, ... ); for my $h (@aoh) { my @keys_sorted_by_values = sort { $h->{$a} <=> $h->{$b} } keys %$ +h; print "{"; print " $_ => $h->{$_}," for @keys_sorted_by_values; print "},"; } __END__ { 4 => 8, 5 => 9, 3 => 15, }, { 5 => 6, 3 => 11, 4 => 25, }, ...

    Note that this doesn't sort the original hashes' entries (in place), i.e. the order as returned by keys, values or each. The latter cannot be achieved this way because hashes have their own intrinsic ordering (appears pseudo-random), which is the result of the particular hashing function being used.  In other words, you cannot sort a hash itself, but only what you read from it, e.g. for printing out, or some other processing.

      foreach(@aoh) { my %a = %$_; my %c= reverse %a; foreach my $key (sort { $a <=> $b } keys%c) { print "$key=> $c{$key}\n"; } print "\n"; }
        foreach(@aoh) { my %a = %$_; my %c= reverse %a;

        The problem with reversing the hash is that if the values aren't unique, e.g.

        { 3 => 15, 4 => 8, 5 => 8, },

        you won't get the desired result...  So why impose unnecessary restrictions for no real gain?  For any reasonably sized hash, creating a reversed copy of it will approximately outweigh the benefits of not having to dereference in the sort function.

        Also, there's no need to create an extra temp hash %a, just write

        my %c = reverse %$_;
        Try this things.....
        foreach $hash ( @aoh) { my %new = reverse (%{$hash}); foreach ( sort {$a <=> $b } keys (%new )) { print " $new{$_} :$_ \n "; } print "-------------\n"; }