2

我有两个数组:

  1. @array1包含blah1通过blah100.
  2. @array2包含Name: creating "blah1"通过Name: creating "blah100".

我需要检查其中的每个元素@array1是否在其中,@array2但该Name: creating部分正在妨碍。

确保所有元素@array1都在的最佳途径是@array2什么?

也许在循环遍历时使用正则表达式进行@array1匹配@array2
还有另一种更快的方法吗?

当其中一个数组中有嘈杂的字符串时,是否array_diff可以intersect工作?unique

或者

也许操纵@array2 使其摆脱Name: creating每个数据的一部分?

哪种方式会更快?

4

5 回答 5

4
die if @array1 != @array2;
for (0..$#array1) {
   die if $array2[$_] ne qq{Name: creating "$array1[$_]"};
}

或者如果名称部分是可变的,

die if @array1 != @array2;
for (0..$#array1) {
   die if $array2[$_] !~ /: creating "\Q$array1[$_]\E"$/;
}
于 2013-07-31T21:29:29.677 回答
1

我会用相同的规则对两个数组进行排序,然后一一比较。

use strict;
use warnings;

sub checkall{
my @array1 = @{shift};
my @array2 = @{shift};

my @sorted1 = sort{ $a <=> $b } @array1;
my @sorted2 = sort{ $a <=> $b } @array2;

if( $#sorted1 == $#sorted2){
  for(0 .. $#sorted1)
  {
    #print $sorted1[$_] ."->". $sorted2[$_] ."\n"; #uncomment to see the comparison
    return "doesn't match!" if not $sorted1[$_] eq $sorted2[$_];
  }
  return "ok!";
}else
  {
    return "not same size!";
  }
}

my @array1 = (4,2,3,1);
my @array2 = (1,2,3,4);
print checkall(\@array1,\@array2);

另一个更接近问题要求的版本:

sub checkall{
    my @array1 = @{shift};
    my @array2 = @{shift};
    my $aux;

    my @sorted1 = sort ( map{ ($aux) = $_ =~ /Name\: creating \"(.*)\"/g } @array1 );
    my @sorted2 = sort @array2;

    if( $#sorted1 == $#sorted2){
      for(0 .. $#sorted1)
      {
        #print $sorted1[$_] ."->". $sorted2[$_] ."\n"; #uncomment to see the comparison
        return "doesn't match!" if not $sorted1[$_] eq $sorted2[$_];
      }
      return "ok!";
    }else
      {
        return "not same size!";
      }
    }

不同之处在于创建一个带有地图和模式的新列表。

于 2013-07-31T21:35:08.817 回答
1

我会使用 map 从第二个数组中过滤所需的部分,然后将两者与智能匹配运算符 (~~) 进行比较:

#!/usr/bin/perl

use strict;
use warnings;

my @arr1 = qw(blah1 blah2 blah3);
my @arr2 = ('Name: creating "blah1"','Name: creating "blah2"','Name: creating "blah3"');

my @compare = map { local $_ = $_; s/^.+\: creating "([a-zA-Z0-9]+)"/$1/; $_ } @arr2;

if (@arr1 ~~ @compare){
    print "all blahs there\n";
}

在这个例子中,它假设两个数组都已经排序,如果不只是使用“排序”的话。

于 2013-07-31T21:47:53.657 回答
1

示例数据

my @array1 = qw(blah1 blah2);
my @array2 = split(';', 'Joe: creating "blah1";Bill: creating "blah2"');

以下前两行是您问题的解决方案

my @check = map { m/:.*?"(.*)"/g } @array2;
if (@array1 == @array2 && "@array1" eq "@check") {
    # note that @array1 == @array2 is only done for efficiency;
    # it would be sufficient to verify only that
    # "@array1" eq "@check"
    print "same\n";
} else {
    print "different\n";
}

请注意,现在排序是安全的@array1@check以防您的原始数组没有相应的顺序。(排序@array并且@array2只会破坏任何可能已经存在的订单,因为名称以 . 中的值作为前缀@array2。)

my @check = map { m/:.*?"(.*)"/g } @array2;
my $i = 0;
if (@array1 == @array2) {
    for (; $i < @array1; $i++) {
        last if $array1[$i] ne $check[$i];
    }
} else {
    $i = -1;
}
if ($i == @array1) {
    print "same\n";
} else {
    print "different\n";
}

请注意,只有当您的数组不相同时,这个较长的代码才会更有效。如果通常情况下您希望数组的值相同,那么使用较长的代码没有任何好处。

顺便说一句:那个正则表达式看起来很粗心,但根据 OP,它正是我们想要的,特别是如果 blah1、blah2 等可能包含额外的双引号。如果我们确定没有名称包含引号,那么我们可以删除:.*?"(.\*)"单独执行,这样会更快。

于 2013-07-31T22:01:55.180 回答
1

这应该是最快的,但与ikegami解决方案相比只有很小的幅度

die if @array1 != @array2;
my $i;
for my $e (@array1) {
   die if $array2[$i++] ne qq{Name: creating "$e"};
}

编辑

如果字符串的名称部分是可变的:

die if @array1 != @array2;
my $i;
for my $e (@array1) {
   die if $array2[$i++] !~ m/: creating "\Q$e\E"/;
}
于 2013-07-31T22:36:17.617 回答