Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I sort a Perl hash on values and order the keys correspondingly (in two arrays maybe)?

In Perl, I want to sort the keys of a hash by value, numerically:

{   five => 5   ten => 10   one => 1   four => 4 } 

producing two arrays:

(1,4,5,10) and (one, four, five, ten) 

And then I want to normalize the values array such that the numbers are sequential:

(1,2,3,4) 

How do I do this?

like image 616
Gogi Avatar asked Jun 05 '12 16:06

Gogi


People also ask

How do I sort hash hash in Perl?

For example we can sort the hash first by the Position value, and among the entries with the same Position value we can sort by the value of the Max field. In order to do this we will use the following expression: my @maxed = sort { $data->{$a}{Position} <=> $data->{$b}{Position}

How do I sort in Perl?

Perl | sort() Functionsort() function in Perl is used to sort a list with or without the use of method of sorting. This method can be specified by the user in the form of subroutines or blocks. If a subroutine or block is not specified then it will follow the default method of sorting.

How get key from hash value in Perl?

Extracting Keys and Values from a Hash variable The list of all the keys from a hash is provided by the keys function, in the syntax: keys %hashname . The list of all the values from a hash is provided by the values function, in the syntax: values %hashname . Both the keys and values function return an array.


2 Answers

First sort the keys by the associated value. Then get the values (e.g. by using a hash slice).

my @keys = sort { $h{$a} <=> $h{$b} } keys(%h); my @vals = @h{@keys}; 

Or if you have a hash reference.

my @keys = sort { $h->{$a} <=> $h->{$b} } keys(%$h); my @vals = @{$h}{@keys}; 
like image 63
ikegami Avatar answered Sep 20 '22 17:09

ikegami


How do I sort a hash (optionally by value instead of key)?

To sort a hash, start with the keys. In this example, we give the list of keys to the sort function which then compares them ASCIIbetically (which might be affected by your locale settings). The output list has the keys in ASCIIbetical order. Once we have the keys, we can go through them to create a report which lists the keys in ASCIIbetical order.

my @keys = sort { $a cmp $b } keys %hash;  foreach my $key ( @keys ) {     printf "%-20s %6d\n", $key, $hash{$key}; } 

We could get more fancy in the sort() block though. Instead of comparing the keys, we can compute a value with them and use that value as the comparison.

For instance, to make our report order case-insensitive, we use lc to lowercase the keys before comparing them:

my @keys = sort { lc $a cmp lc $b } keys %hash; 

Note: if the computation is expensive or the hash has many elements, you may want to look at the Schwartzian Transform to cache the computation results.

If we want to sort by the hash value instead, we use the hash key to look it up. We still get out a list of keys, but this time they are ordered by their value.

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

From there we can get more complex. If the hash values are the same, we can provide a secondary sort on the hash key.

my @keys = sort { $hash{$a} <=> $hash{$b} or "\L$a" cmp "\L$b" } keys %hash; 
like image 28
Eric Leschinski Avatar answered Sep 23 '22 17:09

Eric Leschinski