Perl哈希的最小值和最大值

Perl哈希的最小值和最大值,perl,hash,max,min,Perl,Hash,Max,Min,这是另一个关于perlmonks的问题的变体,与我试图解决的问题类似。我有下面的散列 %Year = ( 2007 => { ID1 => 07, ID4 => 34, ID2 => 24, ID9 => 14, ID3 => 05, }, 2008 => { ID7 => 11, ID9 => 64, ID10 => 20, ID5 =

这是另一个关于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。这可以用计算机来完成吗

预期结果:

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

除非列表很大,否则最好通过对整个哈希进行排序并选取前两个和后两个元素来找到两个最大和两个最小的哈希值

您对输出的期望似乎不正确。对于2008年,按值排序的散列数据如下所示

ID7  => 11
ID5  => 13
ID10 => 20
ID8  => 22
ID9  => 64
因此
max1
max2
ID9
ID8
,而
min1
min2
ID7
ID5
。但是你的问题是,你认为<代码> Max 2>代码>是<代码> ID10,其值为20 -在排序范围的中间。我认为
max2
应该是
ID8
,它的值为22,是2008年散列中的第二大值

我建议使用此解决方案来产生我认为您想要的输出

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];
}
您有散列,并在列表/数组上工作。这就取消了你的资格,因为钥匙和数据对你来说仍然很重要

可以创建第二个由数据设置关键字的散列,然后我可以使用
List::Util
List::MoreUtils
中的内容来提取所需的数据,然后查找该数据的关键字。然而,仅仅为了获得你想要的信息就需要做大量的工作

实际上,您并不是在对散列进行排序,而是在对每年的数据进行排序。这使工作容易多了

通常,当您对散列进行排序时,您是在对键进行排序。但是,您可以在sort命令中指定一个子例程来更改Perl排序的方式。Perl将为您提供两个项目
$a
$b
,它们表示哈希的键。找出哪个更大,然后将其传递回Perl。Perl为数字提供
,为非数字数据提供
cmp

我所要做的就是指定
sort{$array{$a}cmp$array{$b}}键%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

TIMTOWDI:您已经提到了散列的散列,因此您可以按值对内部散列排序并获取一个片段(即前两个和后两个元素)


为什么要使用
List::Util
模块执行此操作?我想看一看。@Borodin-我用它来查找最小值和最大值,但不知道如何使用相应的键执行此操作。还有如何使用它来找到下一个最佳的最小值和最大值。这个问题不是List::Util所特有的。我只是问这个模块是否可行。任何建议的解决方案都将不胜感激。无需复制每年的哈希值。使用
my$id\u hash=$year{$year}
复制引用,并在您拥有
$id\u hash{$key}
的任何地方使用
$id\u hash{$key}
before@David-我似乎没有得到正确的最大和最小值。@user2674514编程,所有答案都是相似的。这里的关键是排序行,在该行中,您根据哈希的内容而不是哈希进行排序。杰帕尔的回答把一切都压缩成一句话。我把它拼出来。然而,一个关键区别是我使用
cmp
按字符串排序,而其他人使用
按数字排序。我这样做是因为有一个数据项是零填充的。对我来说,这意味着数据可能是字符串数据。在我的程序中将
cmp
更改为
,它将与其他程序一样工作。@David-感谢您的澄清。是的,更改为将提供正确的结果。Year是哈希的名称,而不是%data。@user2674514:啊,您在问题中显示了哈希引用,所以我假设Year是另一个哈希的元素。好的,我已经修正了你的问题和我的答案。@user2674514:啊,你在问题中显示一个哈希引用,并使用
Year
而不是
%Year
。您还可以在整个过程中使用
=
而不是
=>
,因此我假设
是另一个散列的元素。好的,我已经修正了你的问题和我的答案。这很有效。如何将它们映射到另一个散列中,而不是打印到std out?这样我就可以在内存中进行进一步的操作。@user2674514您想如何将其存储在哈希中?就像原始散列的布局一样?%storehash=(ID4=>{'value'=>34',type'=>max1',year'=>2007},ID2=>{'value'=>24',type'=>max2',year'=>2007},ID3=>{'value'=>05',type'=>min1',year'=>2007},ID1=>{'value'=>07',type'=>min2',year'=>2007},ID9=>{'value'=>64',type'=>max1',year'=>2008},ID8=>{'value'=>22',type'=>max2',year'=>2008},ID7=>{'value'=>11',type'=>min1',year'=>2008},ID5=>{'value'=>13',type'=>min2',year'=>2008},)@user2674514:你不能有这样的散列,因为同一个ID可以出现在一年以上的数据中
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
#!/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