如何确定数组中是否存在元素(perl)

时间:2012-07-06 15:25:17

标签: perl

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

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

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 = 0)正在测试的阵列。我只是不明白。

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

  @array=`cat file`;

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

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

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

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

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

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

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

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

我正在搜索的术语存储在一个变量中,该变量通过split:

实例化
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在那里?它不能正常工作......即使它绝对不在array2中,它也是$ term2的所有值的成功... array1是一个几千行的文件。我在这里调用$ term2的元素是一个离散项,可以是多行,但在任何给定行中都不会重复(或者是较大字符串的一部分)。 Array2是我需要“过滤”输出的几十个元素。

...

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

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

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

8 个答案:

答案 0 :(得分: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) })进行检查。

<强> ETA:

使用已更改的问题:如果任务是将@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

答案 1 :(得分: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。 我应该补充一点,不是每个人都喜欢~~因为有一些歧义,嗯,“没有文档的功能”。应该可以这样做。

答案 2 :(得分: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.

答案 3 :(得分: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 )) ;
}

答案 4 :(得分:1)

模式匹配是匹配元素的最有效方式。这样就可以了。干杯!

print "$element found in the array\n" if ("@array" =~ m/$element/);

答案 5 :(得分:0)

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

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

应该是:

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

您的代码中有不平衡的括号。您可能还会发现使用grep与对其参数(数组)进行操作的回调(代码引用)更容易。它有助于保持括号不会模糊在一起。但这是可选的。它将是:

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

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

答案 6 :(得分:0)

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

#! /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

答案 7 :(得分: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";
    }