【问题标题】:Why is this reduce {} not returning the max value as expected?为什么这个 reduce {} 没有按预期返回最大值?
【发布时间】:2015-03-21 15:05:51
【问题描述】:

我需要找到 Perl 哈希中所有值的最大值。我不需要密钥,只需要最高值,这样我就可以增加它并返回一个比以前更高的新值。世界上最简单的事情。我从这个答案中得到灵感:https://stackoverflow.com/a/2891180/2740187,并实现了这段代码:

use List::Util qw( reduce min max );
my %gid = ("abc" => 1, "def" => 1);
my $gid_ref = \%gid;
my $max_gid = reduce { $a > $b ? $a : $b } values %$gid_ref || 0;
print "$max_gid\n"; 

如您所见,哈希仅包含两个 1 作为值。那为什么要打印“2”?至少在我的机器上是这样。

我想我会写

my $max2 = max(values %$gid_ref) || 0;

无论如何要获得最大值,但我真的很想了解这里发生了什么。

【问题讨论】:

  • “我想我可以写my $max2 = max ...”这就是所谓的“自我记录代码”。 max 一目了然,而reduce 需要额外的一秒钟来解析。当您有多种方法来解决同一个问题时,您通常应该使用最易读的方法。
  • 完全同意,我会在我的代码中这样做。我刚刚偶然发现了该解决方案并在不久前使用了它。但是一个人永远不会停止学习......

标签: perl hash max reduce


【解决方案1】:

这一行

my $max_gid = reduce { $a > $b ? $a : $b } values %$gid_ref || 0;

被解析为

my $max_gid = reduce { $a > $b ? $a : $b } (values %$gid_ref || 0);

(values %$gid_ref || 0)

在标量上下文中使用values,其计算结果为散列中的元素数 (2)。由于 2 || 0 仍然是 2,因此您对标量执行归约并取回值。

另一方面

my $max_gid = (reduce { $a > $b ? $a : $b } values %$gid_ref) || 0;

确实按预期获得了序列的最大值。

|| 0 的目的是什么?文档推荐

如果您的算法要求 reduce 产生一个标识值,请确保始终将该标识值作为第一个参数传递,以防止返回 undef。

所以你可能想要

my $max_gid = reduce { $a > $b ? $a : $b } 0, values %$gid_ref;

【讨论】:

  • 我认为你的意思是 (0, values %$gid_ref) 最后一点。
  • @cjm:感谢您发现这一点。事实上0 应该在values 之前
  • 可能需要注意 values $gid_ref 仅适用于 Perl 5.14+ 并且 feature “被认为是高度实验性的”。
  • @Ben Voigt,不是在标量上下文中,不是。在标量上下文中返回列表是不可能的。由每个运算符决定它们在标量上下文中返回的内容。 (实际上,标量上下文中的列表返回列表的最后一个元素,而不是列表中元素的数量。例如perl -E'say scalar( 5,6,7 )'
  • 鉴于此,元素的数量是最明智的返回
【解决方案2】:

您也可以使用较低优先级的or 运算符而不是||,这不会对values() 施加标量上下文

my $max_gid = (reduce { $a > $b ? $a : $b } values %$gid_ref or 0);

(括号在这里是强制性的,如果你省略它们,警告会报错)

【讨论】:

  • 我真的不明白优先级错误的运算符如何优于另一个优先级错误的运算符。我猜是因为警告?
  • @BenVoigt 我不知道我在追随你的想法。你有什么想法?
猜你喜欢
  • 1970-01-01
  • 2014-11-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-14
  • 2021-01-11
  • 1970-01-01
  • 2020-07-24
相关资源
最近更新 更多