Sort multidimensional hash by values and print the highest

淺唱寂寞╮ 提交于 2020-03-01 05:29:51

问题


I have a stored multidimensional hash (%info) with 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.

Any help?


回答1:


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}";



回答2:


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";



回答3:


Sometimes the hardest thing to do is precisely to define the problem. Try this code:

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

my %info = (
    Debian  => { jessie => 80, buster => 90, bullseye => 110 },
    Fedora  => { fedora_a => 70, fedora_b => 105 },
    Arch    => { arch_a => 50, arch_b => 108 },
    Windows => { vista => 40, win10 => 63 },
    OSX     => { apple => 71 },
);

my @key_pairs_unsorted;
for my $os (keys %info) {
    for my $id (keys %{$info{$os}}) {
        push @key_pairs_unsorted, {os => $os, id => $id};
    }
}
my @key_pairs_sorted =
  sort { $info{$b->{os}}{$b->{id}} <=> $info{$a->{os}}{$a->{id}} }
  @key_pairs_unsorted;

printf "%-7s %-8s %3d\n",
  $_->{os}, $_->{id}, ${info}{$_->{os}}{$_->{id}}
  for @key_pairs_sorted;

Understanding this code should help you precisely to define your problem, after which you should be able to solve the problem reasonably swiftly.

For further reference, this question or this one might be of interest.



来源:https://stackoverflow.com/questions/59013504/sort-multidimensional-hash-by-values-and-print-the-highest

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!