在Perl中获取具有最高值的密钥的最简单方法是什么?

syk*_*ker 21 perl hash max

在Perl中获取具有最高值的密钥的最简单方法是什么?

Eri*_*rom 34

虽然排序的解决方案:

(sort {$hash{$a} <=> $hash{$b}} keys %hash)[0]
Run Code Online (Sandbox Code Playgroud)

在其他一些答案中发现它非常优雅,它的表现不如它看起来那么好.首先,排序将O(n)搜索搜索操作转换为O(n log n)一个.其次,排序解决方案具有n log n哈希查找.哈希查找起坐某些操作非常好,但与整个哈希工作时,看起坐会比使用速度较慢each,keysvalues通过数据结构进行迭代.这是因为迭代器不需要计算键的哈希值,也不需要反复遍历块来查找值.并且开销不是恒定的,而是随着哈希变大而增加.

以下是一些更快的解决方案:

use strict;
use warnings;

my %hash = (
    small   => 1,
    medium  => 5,
    largest => 10,
    large   => 8,
    tiny    => 0.1,
);
Run Code Online (Sandbox Code Playgroud)

这是一个使用each迭代器的解决方案(O(1)操作完成n次数):

sub largest_value (\%) {
    my $hash = shift;
    keys %$hash;       # reset the each iterator

    my ($large_key, $large_val) = each %$hash;

    while (my ($key, $val) = each %$hash) {
        if ($val > $large_val) {
            $large_val = $val;
            $large_key = $key;
        }
    }
    $large_key
}

print largest_value %hash; # prints 'largest'
Run Code Online (Sandbox Code Playgroud)

或者是一个更快的版本,用于交换内存以获得速度(它会生成哈希的副本):

sub largest_value_mem (\%) {
    my $hash   = shift;
    my ($key, @keys) = keys   %$hash;
    my ($big, @vals) = values %$hash;

    for (0 .. $#keys) {
        if ($vals[$_] > $big) {
            $big = $vals[$_];
            $key = $keys[$_];
        }
    }
    $key
}

print largest_value_mem %hash; # prints 'largest'
Run Code Online (Sandbox Code Playgroud)

以下是各种散列大小的性能:

10 keys:              Rate largest_with_sort largest_value largest_value_mem
largest_with_sort 111565/s                --           -8%              -13%
largest_value     121743/s                9%            --               -5%
largest_value_mem 127783/s               15%            5%                --

50 keys:             Rate  largest_with_sort largest_value largest_value_mem
largest_with_sort 24912/s                 --          -37%              -40%
largest_value     39361/s                58%            --               -6%
largest_value_mem 41810/s                68%            6%                --

100 keys:            Rate  largest_with_sort largest_value largest_value_mem
largest_with_sort  9894/s                 --          -50%              -56%
largest_value     19680/s                99%            --              -12%
largest_value_mem 22371/s               126%           14%                --

1,000 keys:         Rate   largest_with_sort largest_value largest_value_mem
largest_with_sort  668/s                  --          -69%              -71%
largest_value     2183/s                227%            --               -7%
largest_value_mem 2341/s                250%            7%                --

10,000 keys:        Rate   largest_with_sort largest_value largest_value_mem
largest_with_sort 46.5/s                  --          -79%              -81%
largest_value      216/s                365%            --              -11%
largest_value_mem  242/s                421%           12%                --
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,如果内存不是问题,那么内部数组的版本最快,紧跟each迭代器的版本,以及遥远的第三...sort

  • 彻底回答。不过有一个评论:散列查找的摊销复杂度是 O(1),而不是 O(log n)。 (3认同)

Dav*_*man 9

不知道为什么每个人都是手工做这个...

use List::Util qw( reduce );
my $max_val_key = reduce { $hash{$a} > $hash{$b} ? $a : $b } keys %hash;
Run Code Online (Sandbox Code Playgroud)


jka*_*cki 6

与排序哈希的其他答案相比,以下更节省空间并且将以O(n)而不是O(n log n)运行.它假定值是大于0的整数,并且散列不是空的,但应该很容易扩展为您的情况.

my $key_for_max_value;
my $max_value = -1;
while ((my $key, my $value) = each %hash) {
  if ($value > $max_value) {
    $max_value = $value;
    $max_key = $key;
  }
}
Run Code Online (Sandbox Code Playgroud)

$ key_for_max_value现在将是与最高值对应的键.

  • 在您的代码中有一个假设,哈希的值不是所有小于-1的负数.你应该让$ max_value看到第一件东西或者其他东西的价值. (4认同)
  • 很高兴知道_someone_在那里仍然欣赏效率而不是短手.也很好解释. (3认同)
  • @Alnitak具有较小的常数因子.令f(n)= n*log(n)/ log(10)并且g(n)= n*1000000.f(n)= O(n log n)并且g(n)= O(n).现在让n = 10.f(10)是10,g(10)是1000万.此外,只要n小于百万分之一,f(n)将小于g(n).尽管事实上f(n)支配g(n). (2认同)
  • @hobbs我不认为这个解决方案会比涉及排序的解决方案慢.你的论证一般是有效的(常数因子可以使小(n)n优于O(n log n)),但在这种情况下,O(n)解的常数因子很小:我们只看一次每个元素并做一个使用它进行非常少量的计算.最后,这个解决方案的真正胜利是节省空间.排序将占用O(n)空间,而此解决方案需要O(1)空间.有关其他讨论和性能数字,请参阅@Eric Strom答案. (2认同)