3

如果我有一个哈希

my %foo = ( foo => 1, bar => 1 );

我想检查是否有任何键%foo在比较数组中(显然键 %foo 只是一个数组)。我一直在想一些不存在的奇怪语法。

my @cmp0 = qw( foo baz    );
my @cmp1 = qw( baz blargh );

if keys %foo in @cmp0 # returns true because key foo is in the array
if keys %foo in @cmp1 # returns false because no key in foo is an element of cmp1

最简单的方法是什么?

4

5 回答 5

7

List::MoreUtils有一个调用的函数any,它使用类似于 的语法grep,但在第一次满足条件时停止其内部循环。这种行为的优点是需要的迭代次数要少得多(假设交叉点的随机分布)。

另一个优点any是代码清晰:它以它的作用命名。Perl 最佳实践不鼓励grep在布尔上下文中使用,因为假定使用 forgrep是返回匹配的元素列表。它在布尔上下文中工作,但对于读者来说,代码的意图不如any专门为布尔使用而设计的那样清楚。

确实any添加了对 List::MoreUtils 的依赖。然而,List::MoreUtils 是那些无处不在的模块之一,它很可能已经安装了。

这是一个例子:

use List::MoreUtils qw( any );

my %foo = ( foo => 1, bar => 1 );

my @cmp0 = qw( foo baz    );
my @cmp1 = qw( baz blargh );

print "\@cmp0 and %foo have an intersection.\n" 
    if any { exists $foo{$_} } @cmp0;

print "\@cmp1 and %foo have an intersection.\n"
    if any { exists $foo{$_} } @cmp1;

另一个选项是~~ Smart Match Operator,它在 Perl 5.10.0 和更新版本中可用。它可以这样使用:

my %foo = ( foo => 1, bar => 1 );

my @cmp0 = qw( foo baz    );
my @cmp1 = qw( baz blargh );

print "\@cmp0 and %foo have an intersection.\n" if @cmp0 ~~ %foo;

print "\@cmp1 and %foo have an intersection.\n" if @cmp1 ~~ %foo;

使用 smartmatch,您消除了 List::MoreUtils 依赖,取而代之的是最小的 Perl 版本依赖。代码是否像any.

于 2012-06-11T01:28:54.510 回答
5

最简洁的写法是和操作符grep一起使用exists

这段代码

my %foo = ( foo => 1, bar => 1 );

my @cmp0 = qw( foo baz    );
my @cmp1 = qw( baz blargh );

print "YES 0\n" if grep { exists $foo{$_} } @cmp0;
print "YES 1\n" if grep { exists $foo{$_} } @cmp1;

给出这个输出

YES 0
于 2012-06-11T00:42:23.317 回答
5

grep是个好主意,而且可能是最干净的。但是,您也可以使用逻辑 OR 赋值运算符||=

my $found;
$found ||= exists $foo{$_} for @cmp1;
于 2012-06-11T00:59:52.820 回答
1

这些都是简单的集合操作

use strictures;
use Set::Scalar qw();
⋮
my $foo = Set::Scalar->new(keys %foo);
$foo->intersection(Set::Scalar->new(@cmp0))->size; # 1
$foo->intersection(Set::Scalar->new(@cmp1))->size; # 0
于 2012-06-11T08:45:55.233 回答
0

有 - 像往常一样 - 更多的方法来解决这个问题。你可以这样做:

#!/usr/bin/perl

use strict ;
use warnings ;

my %hash = ( foo => 1 , bar => 1 ) ;
my %cmp = ( cmp0 => [ qw(foo baz) ] ,
            cmp1 => [ qw(baz blargh) ] ) ;

my @hash_keys = keys %hash ;
foreach my $compare ( keys %cmp ) {
  my %tmp ;
  # Generate a temporary hash from comparison keys via hash slice
  @tmp{@{$cmp{$compare}}} = undef ;
  INNER:
  foreach my $hash_key ( @hash_keys ) {
    if( exists $tmp{$hash_key} ) {
      printf "Key '%s' is part of '%s'.\n" , $hash_key , $compare ;
      last INNER ;
    }
  }
}

这给出了:

Key 'foo' is part of 'cmp0'.
于 2012-06-11T00:16:11.827 回答