12

我正在遍历一个数组,我想测试是否在另一个数组中找到了一个元素。

在伪代码中,我想做的是:

foreach $term (@array1) {
    if ($term is found in @array2) { 
        #do something here
    }
}

我已经得到了“foreach”和“在这里做点什么”部分向下拍......但是我为“如果在数组中找到术语”测试所做的一切都不起作用......

我试过grep:

if grep {/$term/} @array2 { #do something }
# this test always succeeds for values of $term that ARE NOT in @array2

if (grep(/$term/, @array2)) { #do something }
# this test likewise succeeds for values NOT IN the array

我已经尝试了几种不同风格的“将数组转换为哈希”,许多以前的帖子都表明它们是如此简单和容易……但它们都没有奏效。

我是 perl 的长期低级用户,我只了解 perl 的基础知识,不了解包含我在互联网上阅读的 99% 解决方案的所有花哨的混淆代码......我真的,真的,老实说,感谢代码中明确的任何答案,并提供代码在做什么的分步解释......

...我真的不了解 $_ 和任何其他类型或类型的隐藏、理解或隐含的值、变量或函数。如果任何示例或示例的所有变量和函数都以明确的术语命名($term 而不是 $_),我将非常感激......可能希望有一天能够理解它。请。:-)

...

我有一个现有的脚本,它成功地使用了“grep”:

$rc=grep(/$term/, @array);
if ($rc eq 0) { #something happens here }

但是我将完全相同的代码应用到我的新脚本中,但它根本没有正确成功......即,当它测试我知道数组中不存在的 $term 值时它“成功”(rc = 零)测试。我只是不明白。

'旧'脚本和'新'脚本之间的'grep'方法的唯一区别是我如何构建数组......在旧脚本中,我通过从文件中读取来构建数组:

  @array=`cat file`;

而在新脚本中,我将数组放在脚本本身中(因为它很小)......像这样:

  @array=("element1","element2","element3","element4");

这怎么会导致 grep 函数的不同输出?它们都是沼泽标准阵列!我不明白!!!!:-(

################################################# ######################

附录...我的实际代码的一些说明或示例:

################################################# ######################

我试图匹配/查找/grep 的术语是一个单词元素,例如“word123”。

这个练习只是为了成为一个快速n-dirty脚本,从一个充满垃圾的文件中找到一些重要信息,所以我选择跳过所有细节(使用严格、警告、模块、子例程)......这不是不必优雅,只要简单。

我正在搜索的术语存储在一个通过拆分实例化的变量中:

foreach $line(@array1) {
  chomp($line);  # habit

  # every line has multiple elements that I want to capture
  ($term1,$term2,$term3,$term4)=split(/\t/,$line);  

  # if a particular one of those terms is found in my other array 'array2'
  if (grep(/$term2/, @array2) { 
    # then I'm storing a different element from the line into a 3rd array which eventually will be outputted
    push(@known, $term1) unless $seen{$term1}++;
  }
}

看到那里的 grep 了吗?它工作不正确......它对 $term2 的所有值都成功,即使它绝对不在 array2 中...... array1 是一个几千行的文件。我在这里调用 $term2 的元素是一个离散项,它可能位于多行中,但在任何给定行中都不会重复(或较大字符串的一部分)。Array2 大约有几十个元素,我需要为我的输出“过滤”。

...

我刚刚尝试了以下建议之一:

if (grep $_ eq $term2, @array2) 

对于 $term2 的所有值,这个 grep 都失败了……我从 grep 得到一个全有或全无的响应……所以我想我需要停止使用 grep。尝试其中一种哈希解决方案......但我真的可以使用更多的解释和澄清。

4

8 回答 8

9

这是在perlfaq中。一个快速的方法是

my %seen;
$seen{$_}++ for @array1;
for my $item (@array2) {
    if ($seen{$item}) {
        # item is in array2, do something
    }
}

如果字母大小写不重要,您可以使用 设置键$seen{ lc($_) }并使用 进行检查if ($seen{ lc($item) })

预计到达时间:

更改后的问题:如果任务是将 中的单个单词与 中的@array2整行进行匹配@array1,则任务会更加复杂。由于标点符号和其他类似的东西,尝试拆分行并与哈希键匹配可能是不安全的。因此,正则表达式解决方案可能是最安全的。

除非@array2非常,否则您可能会执行以下操作:

my $rx = join "|", @array2;
for my $line (@array1) {
    if ($line =~ /\b$rx\b/) {  # use word boundary to avoid partial matches
        # do something
    }
}

如果@array2包含元字符,例如*?+|,您必须确保它们被转义,在这种情况下,您会执行以下操作:

my $rx = join "|", map quotemeta, @array2;
# etc
于 2012-07-06T15:47:25.360 回答
6

如果您使用的是 5.10 或更高版本,则可以使用(臭名昭著的)“智能匹配”运算符:

#!/usr/bin/perl
use strict;
use warnings;

my @array1 = qw/a b c d e f g h/; 
my @array2 = qw/a c e g z/; 

print "a in \@array1\n" if 'a' ~~ @array1;
print "z in \@array1\n" if 'z' ~~ @array1;
print "z in \@array2\n" if 'z' ~~ @array2;

该示例非常简单,但如果需要,您也可以使用 RE。我应该补充一点,不是每个人都喜欢~~因为有一些模棱两可的地方,嗯,“未记录的功能”。不过,应该没问题。

于 2012-07-06T15:46:41.617 回答
5

这应该有效。

#!/usr/bin/perl
use strict;
use warnings;

my @array1 = qw/a b c d e f g h/;
my @array2 = qw/a c e g z/;

for my $term (@array1) {
    if (grep $_ eq $term, @array2) {
        print "$term found.\n";
    }
}

输出:

a found.
c found.
e found.
g found.
于 2012-07-06T15:37:03.657 回答
2
#!/usr/bin/perl

@ar = ( '1','2','3','4','5','6','10' );
@arr = ( '1','2','3','4','5','6','7','8','9' ) ;

foreach $var ( @arr ){
    print "$var not found\n " if ( ! ( grep /$var/, @ar )) ;
}
于 2014-02-11T09:21:21.353 回答
1

模式匹配是匹配元素的最有效方式。这可以解决问题。干杯!

print "$element found in the array\n" if ("@array" =~ m/$element/);
于 2016-05-04T12:25:59.480 回答
0

您的“实际代码”甚至不应该编译:

if (grep(/$term2/, @array2) { 

应该:

if (grep (/$term2/, @array2)) { 

您的代码中有不平衡的括号。您可能还会发现将 grep 与对其参数(数组)进行操作的回调(代码参考)一起使用更容易。它有助于防止括号混淆在一起。不过,这是可选的。这将是:

if (grep {/$term2/} @array2) { 

您可能要使用严格;并使用警告;抓住这样的问题。

于 2012-07-06T18:45:06.170 回答
0

下面的示例可能会有所帮助,它会尝试查看@array_sp 中的任何元素是否存在于@my_array 中:

#! /usr/bin/perl -w

@my_array = qw(20001 20003);

@array_sp = qw(20001 20002 20004);
print "@array_sp\n";

foreach $case(@my_array){
    if("@array_sp" =~ m/$case/){
    print "My God!\n";
    }

}

使用模式匹配可以解决这个问题。希望它有所帮助-QC

于 2014-07-04T03:18:56.823 回答
0
1. grep with eq , then 
    if (grep {$_ eq $term2} @array2) { 
    print "$term2 exists in the array";
    }

2. grep with regex , then 
    if (grep {/$term2/} @array2) {
    print "element with pattern $term2 exists in the array";
    }
于 2020-12-22T10:11:45.587 回答