这是对perlmonks提出的另一个问题的变化,类似于我试图弄清楚的问题。我有以下哈希散列。
%Year = (
2007 => {
ID1 => 07,
ID4 => 34,
ID2 => 24,
ID9 => 14,
ID3 => 05,
},
2008 => {
ID7 => 11,
ID9 => 64,
ID10 => 20,
ID5 => 13,
ID8 => 22,
}
)
我想找到两个最小值和两个最大值以及每年的相应ID。可以使用List::Util qw (min max)
完成吗?
期望的结果:
2007 - max1:ID4,34 max2:ID2,24 min1:ID3,05 min2:ID1,07
2008 - max1:ID9,64 max2:ID10,20 min1:ID7,11 min2:ID5,13
答案 0 :(得分:2)
除非列表很大,否则最好通过对整个哈希进行排序并选择前两个和最后一个来找到两个最大和两个最小哈希值两个要素。
您似乎对输出的预期不正确。对于2008年,按值排序的哈希数据类似于
ID7 => 11
ID5 => 13
ID10 => 20
ID8 => 22
ID9 => 64
所以max1
和max2
是ID9
和ID8
,而min1
和min2
是ID7
和{{ 1}}。但是您的问题是,您希望ID5
为max2
,其值为20 - 正好在排序范围的中间。我认为ID10
应该是max2
,其值为22 - 2008哈希值中的第二大值。
我建议使用此解决方案来生成我认为您想要的输出
ID8
<强>输出强>
use strict;
use warnings;
use 5.010;
my %year = (
2007 => { ID1 => 7, ID2 => 24, ID3 => 5, ID4 => 34, ID9 => 14 },
2008 => { ID10 => 20, ID5 => 13, ID7 => 11, ID8 => 22, ID9 => 64 },
);
for my $year (sort { $a <=> $b } keys %year) {
my $data = $year{$year};
my @sorted_keys = sort { $data->{$a} <=> $data->{$b} } keys %$data;
printf "%4d - max1:%s,%02d max2:%s,%02d min1:%s,%02d min2:%s,%02d\n",
$year, map { $_ => $data->{$_} } @sorted_keys[-1,-2,0,1];
}
答案 1 :(得分:0)
您有哈希值,List::Util适用于列表/数组。由于密钥和数据对您来说仍然很重要,因此在那里取消了您的资格。
可以创建由数据键入的第二个哈希,然后我可以使用List::Util
或List::MoreUtils
上的内容来提取您想要的数据,然后查找该数据的键。但是,为了获得您想要的信息,这需要做很多工作。
实际上,你并没有对散列的散列进行排序,而只是对每年的数据进行排序。这使得工作变得更加容易。
通常,在对哈希进行排序时,您需要对键进行排序。但是,您可以在sort命令中指定子例程以更改Perl排序方式。 Perl将向您提供两个$a
和$b
项,它们代表哈希的键。你弄清楚哪个是更大的,并将其传递给Perl。 Perl为您提供<=>
数字和cmp
非数字数据。
我所要做的就是指定sort { $array{$a} cmp $array{$b} } keys %array
按数据排序,而不是键。我只是将排序的键扔到另一个数组中,然后使用索引定位来提取我想要的数据。
#! /usr/bin/env perl
use warnings;
use strict;
use autodie;
use feature qw(say);
use Data::Dumper;
my %year;
#
# Data
#
$year{2007}->{ID1} = "07";
$year{2007}->{ID2} = "24";
$year{2007}->{ID3} = "05";
$year{2007}->{ID4} = "34";
$year{2007}->{ID9} = "14";
$year{2008}->{ID7} = "11";
$year{2008}->{ID9} = "64";
$year{2008}->{ID10} = "20";
$year{2008}->{ID5} = "13";
$year{2008}->{ID8} = "22";
#
# For Each Year...
#
for my $year ( sort keys %year ) {
print "$year - ";
#
# No need to do this dereferencing, but it makes the rest of the code cleaner
#
my %id_hash = %{ $year{$year} };
#
# Now I sort my IDs by their data and not the key names
#
my @keys = sort { $id_hash{$a} cmp $id_hash{$b} } keys %id_hash;
#
# And print them out
#
print "max1:$keys[-1],$id_hash{$keys[-1]} ";
print "max2:$keys[-2],$id_hash{$keys[-2]} ";
print "min1:$keys[0],$id_hash{$keys[0]}, ";
print "min2:$keys[1],$id_hash{$keys[1]}\n";
}
输出结果为:
2007 - max1:ID4,34 max2:ID2,24 min1:ID3,05, min2:ID1,07
2008 - max1:ID9,64 max2:ID8,22 min1:ID7,11, min2:ID5,13
答案 2 :(得分:0)
TIMTOWDI:您已经提到了哈希的哈希,因此您可以按值对内部哈希进行排序并获取切片(即前两个和后两个元素)。
#!/usr/bin/perl
use strict;
use warnings;
my %Year = (
2007 => { ID1 => 7, ID2 => 24, ID3 => 5, ID4 => 34, ID9 => 14 },
2008 => { ID10 => 20, ID5 => 13, ID7 => 11, ID8 => 22, ID9 => 64 },
);
for my $year (keys %Year) {
printf "%4d - max1:%s,%02d max2:%s,%02d min1:%s,%02d min2:%s,%02d\n",
$year,
map { $_, $Year{$year}{$_} }
( sort { $Year{$year}{$b} <=> $Year{$year}{$a} } keys %{$Year{$year}} )[0,1,-1,-2];
}
<强>输出:强>
2007 - max1:ID4,34 max2:ID2,24 min1:ID3,05 min2:ID1,07
2008 - max1:ID9,64 max2:ID8,22 min1:ID7,11 min2:ID5,13