从 Perl 中的哈希中获取具有最高值的键的最简单方法是什么?

发布于 2024-09-02 04:07:08 字数 38 浏览 2 评论 0原文

从 Perl 中的哈希中获取具有最高值的键的最简单方法是什么?

What is the easiest way to get a key with the highest value from a hash in Perl?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

人间不值得 2024-09-09 04:07:08

虽然在其他一些答案中找到的 sort: 解决方案

(sort {$hash{$a} <=> $hash{$b}} keys %hash)[0]

非常优雅,但它的性能并不像看起来那么好。首先,排序将 O(n) 搜索操作转换为 O(n log n) 操作。其次,排序解决方案具有n log n 哈希查找。哈希查找对于某些操作非常有用,但是在处理整个哈希时,查找将比使用 eachkeysvalue 慢 迭代数据结构。这是因为迭代器不需要计算键的哈希值,也不需要重复遍历 bin 来查找值。而且开销不是恒定的,而是随着哈希值变大而增加。

这里有一些更快的解决方案:

use strict;
use warnings;

my %hash = (
    small   => 1,
    medium  => 5,
    largest => 10,
    large   => 8,
    tiny    => 0.1,
);

这是一个使用 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'

或者以内存换取速度的更快版本(它会复制哈希值):

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'

这是不同哈希大小的性能:

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%                --

如您所见,如果内存不是太大问题,则具有内部数组的版本是最快的,接近的接下来是each迭代器,在遥远的第三个......sort

While the solution with sort:

(sort {$hash{$a} <=> $hash{$b}} keys %hash)[0]

found in some of the other answers is quite elegant, it doesn't perform as nicely as it looks. First off, the sort transforms an O(n) search search operation into an O(n log n) one. Secondly, the sort solution has n log n hash look-ups. Hash look-ups are very good for certain operations, but when working with the entire hash, look-ups will be slower than using each, keys, or values to iterate through the data structure. This is because the iterators do not need to calculate the hashes of keys, nor do they need to repeatedly walk through bins to find the values. And the overhead is not constant, but increasing as the hashes get larger.

Here are a few faster solutions:

use strict;
use warnings;

my %hash = (
    small   => 1,
    medium  => 5,
    largest => 10,
    large   => 8,
    tiny    => 0.1,
);

Here is a solution using the each iterator (an O(1) operation done n times):

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'

Or a faster version that trades memory for speed (it makes a copy of the hash):

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'

Here is the performance with various hash sizes:

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%                --

As you can see, if memory isn't much of an issue, the version with internal arrays is fastest, closely followed by the each iterator, and in a distant third... sort

机场等船 2024-09-09 04:07:08

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

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

Not sure why everyone is doing this by hand...

use List::Util qw( reduce );
my $max_val_key = reduce { $hash{$a} > $hash{$b} ? $a : $b } keys %hash;
街角迷惘 2024-09-09 04:07:08

与对哈希进行排序的其他答案相比,以下内容更节省空间,并且将以 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;
  }
}

$key_for_max_value 现在将是对应于最高值的键。

The following is more space-efficient and will run in O(n) instead of O(n log n) as compared to the other answers which sort the hash. It assumes values are integers greater than 0 and the hash is not empty, but should be easily extended for your case.

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;
  }
}

$key_for_max_value will now be the key corresponding to the highest value.

╭⌒浅淡时光〆 2024-09-09 04:07:08

按值排序的键,从最低到最高:

sort { $hash{$a} <=> $hash{$b} } keys %hash

按值排序的键,从最高到最低:

reverse sort { $hash{$a} <=> $hash{$b} } keys %hash

第一个元素

(reverse sort { $hash{$a} <=> $hash{$b} } keys %hash)[0]

将太空飞船替换为 cmp

The keys sorted by value, from lowest to highest:

sort { $hash{$a} <=> $hash{$b} } keys %hash

The keys sorted by value, from highest to lowest:

reverse sort { $hash{$a} <=> $hash{$b} } keys %hash

And the first element

(reverse sort { $hash{$a} <=> $hash{$b} } keys %hash)[0]

Replace the spaceship with cmp to taste.

别靠近我心 2024-09-09 04:07:08
my ($max_key, $max_val) = each %hash or die "hash is empty";
while (my ($key, $val) = each %hash) {
  $max_key = $key, $max_val = $val if $val > $max_val;
}
my ($max_key, $max_val) = each %hash or die "hash is empty";
while (my ($key, $val) = each %hash) {
  $max_key = $key, $max_val = $val if $val > $max_val;
}
挽容 2024-09-09 04:07:08
my $highest_val = (sort { $hash{$a} <=> $hash{$b} } keys %hash)[0];

很可能就是你想要的。

如果你有一个非常大的哈希值,你可能需要使用类似 Schwartzian 变换的东西:

my @array = map {[$hash{$_},$_]} keys %hash;
my $key_with_highest_value = (sort { $a->[0] <=> $b->[0] } @array)[0]->[1]
my $highest_val = (sort { $hash{$a} <=> $hash{$b} } keys %hash)[0];

is likely to be what you want.

If you have a very large hash, you might want to use something like a Schwartzian transform:

my @array = map {[$hash{$_},$_]} keys %hash;
my $key_with_highest_value = (sort { $a->[0] <=> $b->[0] } @array)[0]->[1]
美人迟暮 2024-09-09 04:07:08
my $highest_val = (keys {$hash{$b} <=> $hash{$a}} keys %hash)[0];
my $highest_val = (keys {$hash{$b} <=> $hash{$a}} keys %hash)[0];
荒芜了季节 2024-09-09 04:07:08

如果性能不是问题,我建议采用更文学编程< /a> 解决方案。

use List::Util qw(max);
max keys %hash;

If performance isn't an issue, I'd suggest a more literate programming solution.

use List::Util qw(max);
max keys %hash;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文