Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

how to sort hash of array by value

by Anonymous Monk
on Oct 01, 2007 at 21:51 UTC ( #642006=perlquestion: print w/replies, xml ) Need Help??

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

oh great ones,

I have an hash of array. I would like to be able to sort the hash based on the value of the array. But I cannot get to the array in the hash to be able to sort it. the example below does not work becaue I do not know how to pass the array into the sort routine.

code example :

my %colorhash = ( CCgray => ["0","0","0"], CCwhite => ["1","0","0"], CCgrey => ["0","2","0"], CCBlue => ["0","0","3"], ); foreach $colorname (keys %colorhash) { for my $i (0.. $#{ $colorhash{$colorname} } ){ print "[$i] = $colorhash{$colorname}[$i] "; } print "\n"; } my @light2dark = numsort (keys %colorhash); sub numsort { $colorhash{$a}[0] <=> $colorhash{$b}[0] or $colorhash{$a}[1] <=> $colorhash{$b}[1] or $colorhash{$a}[2] <=> $colorhash{$b}[2] }

Replies are listed 'Best First'.
Re: how to sort hash of array by value
by FunkyMonk (Chancellor) on Oct 01, 2007 at 22:06 UTC
    You forgot to sort it!
    use Data::Dumper; my %colorhash = ( CCgray => [ "0","0","0" ], CCwhite => [ "1","0","0" ], CCgrey => [ "0","2","0" ], CCBlue => [ "0","0","3", ] ); my @light2dark = sort numsort (keys %colorhash); print Dumper \@light2dark; sub numsort { $colorhash{$a}[0] <=> $colorhash{$b}[0] or $colorhash{$a}[1] <=> $colorhash{$b}[1] or $colorhash{$a}[2] <=> $colorhash{$b}[2]; }

    Output:

    $VAR1 = [ 'CCgray', 'CCBlue', 'CCgrey', 'CCwhite' ];

      oops, but it still does not change the order based on the value. There is not change in the hash order.
        The hash order is always random, and has nothing to do with the order in which that hash was created.

        Compare the following snippet with the original:

        use Data::Dumper; my %colorhash = ( CCgray => [ "0","0","0" ], CCwhite => [ "1","0","0" ], CCgrey => [ "0","2","0" ], CCBlue => [ "0","0","3", ] ); my @light2dark = keys %colorhash; print Dumper \@light2dark;

        PS Have you enclosed your original program within <code>...</code> tags yet?

Re: sort hash of array by value
by snopal (Pilgrim) on Oct 01, 2007 at 23:16 UTC

    I'm not sure if this is homework, but you certainly won't get that code to work.

    #!/usr/bin/perl use warnings; use strict; my %colorhash = ( CCgray => ["0","0","0"], CCwhite => ["1","0","0"], CCgrey => ["0","2","0"], CCBlue => ["0","0","3"]); foreach my $colorname (keys %colorhash) { for my $i (0.. $#{ $colorhash{$colorname} } ) { print "$i = $colorhash{$colorname}[$i] "; } print "\n"; } my @light2dark = sort numsort (keys %colorhash); sub numsort { $colorhash{$a}[0] <=> $colorhash{$b}[0] or $colorhash{$a}[1] <=> $colorhash{$b}[1] or $colorhash{$a}[2] <=> $colorhash{$b}[2] }

      Responding to my own post.

      First rule:

      use warnings;
      use strict;

      That's the annoying but seemingly impossible to avoid mantra of a good perl developer. Exclude them at your own risk, and only when you know why you are doing so. You really needed to find out where the code just would not work.

      As previously remarked, your value assignment strategy does not do what you think. Since '=>' is just a sophisticated comma, your hash assignment is interpreted as:

      %colorhash = (CCgray => "0", "0" => "0", CCwhite => "1", "0" => "0", etc.

      I think you can see where this is going. Anonymous arrays are constructed within brackets.

      As mentioned before, the quotes around clearly numeric values are unnecessary.

      Next, for some reason, your example has:

      $colorhash{$colorname}$i

      Obviously, the array brackets are missing.

      You should also research the usage of 'sort'. You defined a sort evaluation call, but didn't call sort to use it.

Re: how to sort hash of array by value
by dwm042 (Priest) on Oct 02, 2007 at 14:44 UTC
    One of the problems with providing a data set that is apparently already sorted is that it's hard to prove that the solution can indeed sort (unless you change the actual sort in use):

    #!/usr/bin/perl use warnings; use strict; my %colorhash = ( CCgray => ["0","0","0"], CCwhite => ["1","0","0"], CCgrey => ["0","2","0"], CCBlue => ["0","0","3"], ); print "Original order of data:\n\n"; foreach my $colorname (keys %colorhash) { printf "For key %-7s : ",$colorname; for my $i (0.. $#{ $colorhash{$colorname} } ){ print "element[", $i,"] = $colorhash{$colorname}[$i] "; } print "\n"; } print "\n\n"; my @light2dark = sort lightsort (keys %colorhash); my @dark2light = sort darksort (keys %colorhash); print "Order, dark is ",join(',',@dark2light), ".\n"; print "Order, light is ",join(',',@light2dark), ".\n"; sub darksort { $colorhash{$b}[0] <=> $colorhash{$a}[0] or $colorhash{$b}[1] <=> $colorhash{$a}[1] or $colorhash{$b}[2] <=> $colorhash{$a}[2] } sub lightsort { $colorhash{$a}[0] <=> $colorhash{$b}[0] or $colorhash{$a}[1] <=> $colorhash{$b}[1] or $colorhash{$a}[2] <=> $colorhash{$b}[2] }
    And the results are:

    C:\Code>perl color-sort.pl Original order of data: For key CCBlue : element[0] = 0 element[1] = 0 element[2] = 3 For key CCgray : element[0] = 0 element[1] = 0 element[2] = 0 For key CCgrey : element[0] = 0 element[1] = 2 element[2] = 0 For key CCwhite : element[0] = 1 element[1] = 0 element[2] = 0 Order, dark is CCwhite,CCgrey,CCBlue,CCgray. Order, light is CCgray,CCBlue,CCgrey,CCwhite.
    Update: cleaner logic
Re: sort hash of array by value
by shmem (Chancellor) on Oct 01, 2007 at 23:11 UTC
    Please use <code> tags around your code. See Writeup Formatting Tips.
    my %colorhash = ( CCgray => "0","0","0", CCwhite => "1","0","0", CCgrey => "0","2","0", CCBlue => "0","0","3", );

    This isn't what you expect. It is the same as

    my %colorhash = ( CCgray => "0", "0" => "0", CCwhite => "1", "0" => "0", CCgrey => "0", "2" => "0", CCBlue => "0", "0" => "3", );

    while you surely want

    my %colorhash = ( CCgray => [ "0","0","0" ], CCwhite => [ "1","0","0" ], CCgrey => [ "0","2","0" ], CCBlue => [ "0","0","3" ], );

    See perlref and perlreftut.

    Ah, and another thing: you don't need quotes around your numbers. The above is better written as

    my %colorhash = ( CCgray => [ 0, 0, 0 ], CCwhite => [ 1, 0, 0 ], CCgrey => [ 0, 2, 0 ], CCBlue => [ 0, 0, 3 ], );

    --shmem

    _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                  /\_¯/(q    /
    ----------------------------  \__(m.====·.(_("always off the crowd"))."·
    ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
Re: how to sort hash of array by value
by apl (Monsignor) on Oct 02, 2007 at 10:01 UTC
    Have a subkey containing the order you wish the colors sorted in (e.g. $colorhash{CCgrey}{rank} = 2;)

    Then you could later loop through colorhash testing the {rank} value.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://642006]
Approved by graff
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others examining the Monastery: (5)
As of 2020-12-02 08:03 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    How often do you use taint mode?





    Results (35 votes). Check out past polls.

    Notices?