问题
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