Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sort multidimensional hash by values and print the highest

Tags:

sorting

hash

perl

I have a stored multidimensional hash (%info) with the following structure:

$info{$os}{$id}=$length;

foreach $os (keys %info){   
    foreach $id (keys %{$info{$os}}){
        print "$os $id => " . $info{$os}{$id} ."\n" if (keys %info > 100);
    }
}

With this, I can read the hash and print only those $os with more than 100 occurrences, but now I would like to print only the $id with highest $length (i.e., values). So I would like to sort the hash by values and print only $os and $id with highest value.

like image 955
Emilio Mármol Sánchez Avatar asked Mar 03 '23 03:03

Emilio Mármol Sánchez


2 Answers

Can use List::Util::reduce to get the key with the largest value, within each top-level key

use List::Util qw(reduce);

for my $os (keys %info) { 
    my $id_max_length = reduce { 
        $info{$os}{$a} > $info{$os}{$b} ? $a : $b 
    } keys %{$info{$os}};

    say "$os --> $id_max_length --> $info{$os}{$id_max_length}";
}

To get the highest value among all keys

my ($max_os, $max_id) = 
    map { $_->[0], $_->[1] }
    reduce { $info{$a->[0]}{$a->[1]} > $info{$b->[0]}{$b->[1]} ? $a : $b }
    map { [$_, max_id_for_os($_)] } 
    keys %info;

say "$max_os -> $max_id -> $info{$max_os}{$max_id}";

sub max_id_for_os {
    my ($os) = @_; 
    reduce { $info{$os}{$a} > $info{$os}{$b} ? $a : $b } keys %{$info{$os}}
}

Or, perhaps simpler, compare in the loop over top-level keys

my ($max_os, $max_id) = do {  # initialize
    my ($os) = keys %info;
    $os, (keys %{$info{$os}})[0];
};

for my $os (keys %info) { 
    my $mid = 
        reduce { $info{$os}{$a} > $info{$os}{$b} ? $a : $b } 
        keys %{$info{$os}};

    ($max_os, $max_id) = ($os, $mid) 
        if $info{$os}{$mid} > $info{$max_os}{$max_id};
}

say "Largest: $max_os -> $max_id -> $info{$max_os}{$max_id}";
like image 109
zdim Avatar answered Mar 15 '23 10:03

zdim


my($maxos,$maxid,$maxlength);
foreach my $os (sort keys %info) {
  foreach my $id (keys %{ $info{$os} }) {
    ($maxos,$maxid,$maxlength) = ($os,$id,$info{$os}{$id})
      if !defined $maxlength || $info{$os}{$id} > $maxlength;
  }
}

print "$maxos $maxid => $maxlength\n";
like image 30
Greg Bacon Avatar answered Mar 15 '23 10:03

Greg Bacon