Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sorting multi-level Perl hash (dynamically based on arithmetic)

How do I sort(and print) a multi-level perl hash based on key value ?

%hash = (
  a => { k1 => 51, k2 => 52, k3 => 53 },
  b => { k1 => 61, k2 => 62, k3 => 63 },
  c => { k1 => 71, k2 => 72, k3 => 73 },
)

For example sort the above hash numerically based on the value of k2? So it should print:

52,62,72

I wanted to know how I can expand sorting single level hashes to multilevel using

sort { $hash{$b} <=> $hash{$a} } keys %hash`

Edit

If I have another hash

my %property = ( a => 7, b => 6, c => 5 )

Can I sort %hash based on numerical value of $hash{key}{k2} * $property{key} using

#!/usr/bin/perl
use strict;
use warnings;

my %hash = (
  a => { k1 => 51, k2 => 52, k3 => 53 },
  b => { k1 => 61, k2 => 62, k3 => 63 },
  c => { k1 => 71, k2 => 72, k3 => 73 },
);

my %property = ( a => 7, b => 6, c => 5 );


foreach (sort { ($hash{$a}{'k2'}*$property{$a}) <=> 
                ($hash{$b}{'k2'}*$property{$b}) } keys %hash)
{
    printf("[%d][%d][%d]\n",
    $hash{$_}{'k2'},$property{$_},$hash{$_}{'k2'}*$property{$_});
}

result should be

72,52,62    as products are (360(72*5),364(52*7),372(62*6))
like image 241
Jean Avatar asked Dec 13 '25 23:12

Jean


2 Answers

Get a list of all values in the hash:

values %hash;

transform a list of hashrefs to the contents of the k2 entry:

map $_->{k2}, @list

oh, skip it if it's undef/doesn't exist:

map $_->{k2} // (), @list

sort a list numerically:

sort { $a <=> $b } @list

connect the dots:

sort { $a <=> $b } map { $_->{k2} // () } values %hash;
like image 147
amon Avatar answered Dec 16 '25 14:12

amon


sort {$hash{$a}{'k2'} <=> $hash{$b}{'k2'}} keys %hash

The spaceship operator numerically compares the left-hand side with the right-hand side. It's most often seen in its simplest case, with

$a <=> $b

but in this case, you want to compare values from a hash and it can do that too.

like image 21
YatesCM Avatar answered Dec 16 '25 13:12

YatesCM