### Sort Values in Hash, While Tracking Keys.

by BioNrd (Monk)
 on Jan 29, 2008 at 02:10 UTC 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.

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?