【问题标题】:Perl: find the max and min values in the array of hashesPerl:在哈希数组中找到最大值和最小值
【发布时间】:2018-03-14 01:54:14
【问题描述】:

我在 Perl 中有以下结构:

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

my %hash = (
    'firstitem' => {
        '1' => ["A","99"],
        '2' => ["B","88"],
        '3' => ["C","77"],
    },
    'seconditem' => {
        '3' => ["C","100"],
        '4' => ["D","200"],
        '5' => ["E","300"],
    },
);

我正在寻找一种方法来找到每个哈希数组中的最大数和最小数。 所以输出将是

firstitem: max:99, min:77
seconditem: max:300, min:100

我的想法是先对辅助键进行排序,然后在 for 循环中进行冒泡排序或其他排序。它看起来不是很优雅和聪明。

    foreach my $k1 (keys %hash) {
        my $second_hash_ref = $hash{$k1};                   
        my @sorted_k2 = sort { $a <=> $b } keys %{$second_hash_ref}; 
        foreach my $i (0..$#sorted_k3){ 
            #bubble sort or other sort
        }
    }

【问题讨论】:

  • 我尝试先对第二个键进行排序,然后根据排序后的键迭代值,然后在 for 循环中进行冒泡排序。已发布
  • @MattJacob 我对这个问题做了一些谷歌搜索,发现了一些类似的问题。但是我的数据结构有点不同。感谢您的回答。

标签: arrays perl sorting hash


【解决方案1】:

List::Util是提供minmax功能的核心模块:

use strict;
use warnings;

use List::Util qw(min max);

my %hash = (
    'firstitem' => {
        '1' => ["A","99"],
        '2' => ["B","88"],
        '3' => ["C","77"],
    },
    'seconditem' => {
        '3' => ["C","100"],
        '4' => ["D","200"],
        '5' => ["E","300"],
    },
);

for my $key (keys(%hash)) {
    my @numbers = map { $_->[1] } values(%{$hash{$key}});
    printf("%s: max: %d, min: %d\n", $key, max(@numbers), min(@numbers));
}

输出:

firstitem: max: 99, min: 77
seconditem: max: 300, min: 100

【讨论】:

  • List::MoreUtils 提供minmax,比同时调用minmax 效率更高。
  • @MattJacob 我可以明确写什么而不是使用$_-&gt;[1]
  • @Luke 我不明白这个问题。
  • @MattJaco 您在 for 循环中使用了 $_-&gt;[1]。我知道它调用数组中的元素。我只是想学习任何其他方式来调用它?喜欢更明确的方式而不是$_-&gt;[1]
  • @Luke 有什么比数组引用位置 1 的元素更明确的呢?
【解决方案2】:

你快到了。

一旦您进入第二级,您需要的是整个数字列表,以便能够找到批次的最大值和最小值。由于您需要子键中所有数组的极值,因此您无需遍历二级键。

此外,您可以获取所有数组内容,除非该数字保证在特定位置。然后使用grepScalar::Util::looks_like_number 过滤掉不是数字的元素。

最后,对键进行排序没有任何好处。

use warnings;
use strict;
use feature 'say';

use Scalar::Util 'looks_like_number';
use List::MoreUtils 'minmax';

my %hash = ( 
    'firstitem' => {
        '1' => ["A","99"], '2' => ["B","88"], '3' => ["C","77"],
    },  
    'seconditem' => {
        '3' => ["C","100"], '4' => ["D","200"], '5' => ["E","300"],
    },  
);


foreach my $k1 (keys %hash) 
{
    my @nums = 
        grep { looks_like_number($_) } 
        map  { @{ $hash{$k1}{$_} } }
        keys %{$hash{$k1}};

    my ($min, $max) = minmax @nums;

    say "$k1: max = $max, min = $min";
}

这将打印预期值。如果您的真实哈希与显示的完全一样,您可以通过values %{$hash{$k1}} 直接提取arrayrefs,并使用map { @$_ } 取消引用它们。

由于您需要两个极端,所以最适合的就是 minmaxList::MoreUtils,这是“最有效的算法”。该算法的性能在 XS 版本的模块中完全实现,而 Perl 版本有一些开销。

还要注意核心 List::Util 模块,其中单独的 minmax 以及其他实用程序。

【讨论】:

  • 太棒了。这是一个很好的解决方案。很高兴知道 grepScalar::Util::looks_like_number。感谢您的快速响应。
猜你喜欢
  • 1970-01-01
  • 2018-04-07
  • 1970-01-01
  • 1970-01-01
  • 2018-07-04
  • 2018-07-04
  • 1970-01-01
  • 2018-05-03
相关资源
最近更新 更多