2010-04-15 75 views
7

我不明白从Programming Perl 3e这个功能的最后一行。这个Perl grep如何确定几个哈希的联合?

这里是你会如何编写通过返回传递给它的所有哈希值发生键的列表确实是一种交集的功能:

@common = inter(\%foo, \%bar, \%joe); 
sub inter { 
    my %seen; 
    for my $href (@_) { 
     while (my $k = each %$href) { 
      $seen{$k}++; 
     } 
    } 
return grep { $seen{$_} == @_ } keys %seen; 
}

我明白%seen是一个哈希这将每个键映射到在提供给该函数的任何散列中遇到的次数。

回答

16

grep将传递给它的列表(在这种情况下,在任何hashrefs中看到的每个元素);并返回仅包含块中表达式为真的元素的列表(本地将$_变量设置为列表中的每个元素)。

让我们看看这个表情是如何计算:

  • @_是传递给子程序的所有参数的阵列 - 在我们的情况下,通过哈希引用列表

  • 在。 $seen{$_} == @_表达式该列表被强制为scalar context(由于==)。

  • 当在标量上下文中使用的,表的计算结果为列表中的元素的数量 - 在上面的示例呼叫,到3中,由于3个hashrefs被传入

因此,对于%seen中的每个密钥(例如,在N个hashrefs中的任一个中看到的每个密钥);表达式$seen{$_} == @_在数值上比较了哈希中元素被看到的次数与哈希总数 - 它只会相等,当然,如果元素在所有传入的哈希中,并且因此是我们想要的交集的成员。

因此,为了总结分析,grep将返回发生在每一个散列(也就是发生N次,其中N是散列数)中的所有键的列表。例如。交叉点。

+0

我喜欢这个最近编辑的键从%seen键。很好的答案,DVK。 – spazm 2010-04-15 05:41:04

+0

非常好。保存了我的一天。我实际上编写了一段代码来理解正在发生的事情,并将我的头撞到了将近一个小时,但无法弄清楚。 – anukalp 2014-11-16 12:25:01

2

该函数的用途是查找传递给它的所有散列中出现的元素。

最后一行grepkeys %seen返回的列表。要确定给定的键是否出现在所有传递给该函数的散列中,我们可以将该键的值%seen与参数inter的值进行比较。

grep块中,将$_设置为keys列表的每个元素,并对某些条件进行测试。

标量上下文中的数组计算为其长度。 @_是传递给子例程的参数数组。 ==运算符将其操作数置于标量上下文中,因此我们可以将$seen{$_}的值与@_的长度进行比较。如果它们是相同的,那么这个关键就出现在所有的哈希中。

3
grep block list 

这将依次将块应用到列表的每个元素,该元素被别名为$ _。如果该块返回true,则将该元素添加到返回的数组中。

在这种情况下

grep { $seen{$_} == @_ } keys %seen 

块是$seen{$_} == @_,这对进行比较的@_看到散列的值。 @_在标量上下文中进行评估,因此返回@_数组中元素的数量。 @_代表当前函数的参数。在这种情况下,(\%foo, \%bar, \%joe)在标量上下文中返回3。我们的清单是keys %seen,它是一个包含%seen中存在的所有密钥的数组。

相当于英文陈述:

  • “给我所有键的列表,从 %seen其中具有 关联的值是关键等于传递给这个函数 元素的数量”
  • “给我一个从 %seen的所有键的列表,其中与 关键的值是3
  • “给我一个列表 个所有具有 值3,即所有来自%seen 存在于每个3个 hashrefs传递给这个函数”