Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

Sort Values in Hash, While Tracking Keys.

by BioNrd (Monk)
on Jan 29, 2008 at 02:10 UTC ( [id://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 (Patriarch) 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
Domain Nodelet?
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?Last hourOther CB clients
Other Users?
Others avoiding work at the Monastery: (4)
As of 2024-04-19 03:48 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found