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

Sort Values in Hash, While Tracking Keys.

by BioNrd (Monk)
on Jan 29, 2008 at 02:10 UTC ( #664825=perlquestion: print w/replies, xml ) Need Help??

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

Monks, I have this bit of code:
use warnings; use Data::Dumper; my $counter = 3; %hash = ( a1_2 => 0.556, a1_3 => 0.345, a2_1 => 0.556, a2_3 => 0.125, a3_1 => 0.345, a3_2 => 0.125, ); print Data::Dumper->Dumpxs([\%hash], [q{*hash}]); for (1 .. $counter) { my @holder = (); my $outer = $_; for (1 .. $counter) { my $inner = $_; if ($outer == $inner) { next; } else { my $tracker = "a$outer\_$inner"; foreach $key (keys %hash) { my $value = $hash{$key}; if ($key eq $tracker) { print "$tracker : $key : $value\n"; push @holder, $value; } } } } @holder_sorted = sort { $a <=> $b } @holder; print "@holder_sorted\n"; # this works to sort the values, but # how do you sort the values while keeping track of the keys? }
The comment in the code asks the question. But for clarity, I want to sort hash values, while keeping track of the keys. Ultimately I want to be able to determine which has the highest value, and then use the key that matches the highest value in another subroutine (not shown). I am stuck, any help/advice would be great!

thanks!

---- Even a blind squirrel finds a nut sometimes.

Replies are listed 'Best First'.
Re: Sort Values in Hash, While Tracking Keys.
by chromatic (Archbishop) on Jan 29, 2008 at 02:29 UTC

    A Schwartzian Transform may do the trick. You need to sort the values, which would be:

    my @values = sort { $a <=> $b } values %hash;

    ... but you need to keep track of the keys as well. You can build a temporary data structure of pairs, or a list of two-element array references, where the first element is the value and the second element is the key:

    my @pairs = map { [ $hash{$_}, $_ ] } keys %hash;

    To get back the keys, you need to map over this list and extract the second element of each pair:

    my @keys = map { $_->[1] } @pairs;

    That looks like a lot of useless work, and it would be, except that you can stick as many list-transforming functions in the middle as you want -- including a sort. You can also drop the temporary arrays; they're unnecessary. The result is:

    my @keys_sorted_by_value = map { $_->[1] } sort { $a->[0] <=> $b->[0] } map { $hash{$_}, $_ } keys %hash;

    Update: Fixed a typo found by Roy Johnson.

Re: Sort Values in Hash, While Tracking Keys.
by GrandFather (Saint) on Jan 29, 2008 at 02:29 UTC

    The "key" is to push value/key pairs on to @holder. Consider:

    use strict; use warnings; use Data::Dumper; my $counter = 3; my %hash = ( a1_2 => 0.556, a1_3 => 0.345, a2_1 => 0.556, a2_3 => 0.125, a3_1 => 0.345, a3_2 => 0.125, ); for my $outer (1 .. $counter) { my @holder = (); for my $inner (1 .. $counter) { next if $outer == $inner; my $tracker = "a$outer\_$inner"; foreach my $key (keys %hash) { next unless $key eq $tracker; my $value = $hash{$key}; print "$tracker : $key : $value\n"; push @holder, [$value, $key]; } } my @holder_sorted = sort { $a->[0] <=> $b->[0] } @holder; print map {"$_->[1] => $_->[0]\n"} @holder_sorted; }

    Prints:

    a1_2 : a1_2 : 0.556 a1_3 : a1_3 : 0.345 a1_3 => 0.345 a1_2 => 0.556 a2_1 : a2_1 : 0.556 a2_3 : a2_3 : 0.125 a2_3 => 0.125 a2_1 => 0.556 a3_1 : a3_1 : 0.345 a3_2 : a3_2 : 0.125 a3_2 => 0.125 a3_1 => 0.345

    Perl is environmentally friendly - it saves trees
Re: Sort Values in Hash, While Tracking Keys.
by ikegami (Pope) on Jan 29, 2008 at 02:33 UTC

    Just hold the keys, not the values.

    push @holder, $key; ... my @holder_sorted = sort { $hash{$a} <=> $hash{$b} } @holder; print("@hash{@holder_sorted}\n");

    Update: I see that people are suggesting that hold both the key and the value. It's unnecessary to hold the value since you already have a convenient way of looking up the value by key: $hash{$key}. But if you want to hold both, might as well use a hash!

    my %holder; ... $holder{$key} = $value; ... my @holder_sorted = sort { $holder{$a} <=> $holder{$b} } keys @holder; print("@holder{@holder_sorted}\n");
Re: Sort Values in Hash, While Tracking Keys.
by hipowls (Curate) on Jan 29, 2008 at 02:30 UTC
    my ( $key, $value ) = @{ # 5. dereference anonymous hash + ( sort { $a->[1] <=> $b->[1] } # 3. sort numerically by value map { [ $_ => $hash{$_} ] } # 2. convert to anonymous array keys %hash # 1. each key )[-1] # 4. get last (highest value) };
Re: Sort Values in Hash, While Tracking Keys.
by BioNrd (Monk) on Jan 29, 2008 at 04:06 UTC
    Thanks much for all the advice. I was unaware of the map function. I should be able to take things from here. Thanks again.

    Bio.

    ---- Even a blind squirrel finds a nut sometimes.

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others perusing the Monastery: (5)
As of 2021-06-24 21:07 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    What does the "s" stand for in "perls"? (Whence perls)












    Results (132 votes). Check out past polls.

    Notices?