Perl在数组中不匹配

时间:2012-01-09 21:06:50

标签: perl

我有两个数组:

@array1 = (A,B,C,D,E,F);
@array2 = (A,C,H,D,E,G);

阵列的大小可能不同。我想知道数组之间有多少不匹配。索引应该是相同的。在这种情况下,有三种不匹配:b->cc->hF->G。(C中的“$array[2]”不应视为与C中的“$array[1]”我想知道不匹配的数量以及不匹配。

foreach my $a1 ( 0 .. $#array1) {
 foreach my $a2( 0 .. $#array2)
  if($array1[$a1] ne $array2[$a2]) {

   }
 }
}

my %array_one = map {$_, 1} @array1;
my @difference = grep {!$array_one {$_}} @array1;

print "@difference\n";

答:给我HG但不是C

凭借我的小Perl知识,我尝试了这一点,没有结果。你能建议我怎么处理这件事吗?您的建议和指示将非常有用。

6 个答案:

答案 0 :(得分:4)

你不应该有嵌套循环。您只需要浏览一次索引。

use List::Util qw( max );

my @mismatches;
for my $i (0..max($#array1, $#array2)) {
   push @mismatches, $i
      if $i >= @array1
      || $i >= @array2
      || $array1[$i] ne $array2[$i];
   }
}

say "There are " . (0+@mismatches) . " mismatches";
for my $i (@mismatches) {
   ...
}

由于您提到grep,因此您可以将for替换为grep

use List::Util qw( max );

my @mismatches =
    grep {  $_ >= @array1
         || $_ >= @array2
         || array1[$_] ne $array2[$_] }
    0 .. max($#array1, $#array2);

say "There are " . (0+@mismatches) . " mismatches";
for my $i (@mismatches) {
   ...
}

答案 1 :(得分:1)

当您不希望这样做时,您正在迭代两个数组。

@array1 = ("A","B","C","D","E","F");
@array2 = ("A","C","H","D","E","G");
foreach my $index (0 .. $#array1) {
   if ($array1[$index] ne $array2[$index]) {
       print "Arrays differ at index $index: $array1[$index] and $array2[$index]\n";
   }
}

输出:

Arrays differ at index 1: B and C
Arrays differ at index 2: C and H
Arrays differ at index 5: F and G

答案 2 :(得分:1)

以下代码构建了不匹配对的列表,然后将其打印出来。

@a1 = (A,B,C,D,E,F);
@a2 = (A,C,H,D,E,G);
@diff = map { [$a1[$_] => $a2[$_]] }
            grep { $a1[$_] ne $a2[$_] }
                 (0..($#a1 < $#a2 ? $#a1 : $#a2));
print "$_->[0]->$_->[1]\n" for @diff

答案 3 :(得分:1)

那么,首先,您将要查看其中一个数组的每个元素,并将其与另一个数组的相同元素进行比较。 List :: MoreUtils提供了一种简单的方法:

use v5.14;
use List::MoreUtils qw(each_array);

my @a = qw(a b c d);
my @b = qw(1 2 3);

my $ea = each_array @a, @b;
while ( my ($a, $b) = $ea->() ) {
    say "a = $a, b = $b, idx = ", $ea->('index');
}

您可以通过检查while循环内部来扩展它以查找不匹配的位置(注意:这假设您的数组最后没有undefs,或者如果它们这样做,则undef与拥有一个较短的数组):

my @mismatch;
my $ea = each_array @a, @b;
while ( my ($a, $b) = $ea->() ) {
    if (defined $a != defined $b || $a ne $b) {
        push @mismatch, $ea->('index');
    }
}

然后:

say "Mismatched count = ", scalar(@mismatch), " items are: ", join(q{, }, @mismatch);

答案 4 :(得分:1)

以下是使用each_arrayref中的List::MoreUtils的示例。

sub diff_array{
  use List::MoreUtils qw'each_arrayref';
  return unless @_ && defined wantarray;
  my @out;

  my $iter = each_arrayref(@_);

  my $index = 0;
  while( my @current = $iter->() ){
    next if all_same(@current);

    unshift @current, $index;
    push @out, \@current;
  }continue{ ++$index }

  return @out;
}

如果您打算使用它来经常确定差异的数量,那么此版本应该更快。输出完全相同。返回一个数字时,它不需要那么努力 了解更多信息,请阅读wantarray

sub diff_array{
  use List::MoreUtils qw'each_arrayref';
  return unless @_ && defined wantarray;

  my $iter = each_arrayref(@_);

  if( wantarray ){
    # return structure
    my @out;

    my $index = 0;
    while( my @current = $iter->() ){
      next if all_same(@current);

      unshift @current, $index;
      push @out, \@current;
    }continue{ ++$index }

    return @out;

  }else{
    # only return a count of differences
    my $out = 0;
    while( my @current = $iter->() ){
      ++$out unless all_same @current;
    }
    return $out;
  }
}

diff_array使用子例程all_same来确定所有当前元素列表是否相同。

sub all_same{
  my $head = shift;
  return undef unless @_; # not enough arguments
  for( @_ ){
    return 0 if $_ ne $head; # at least one mismatch
  }
  return 1; # all are the same
}

获得差异的数量:

print scalar diff_array \@array1, \@array2;
my $count  = diff_array \@array1, \@array2;

获取差异列表:

my @list = diff_array \@array1, \@array2;

同时获得两者:

my $count = my @list = diff_array \@array1, \@array2;

您提供的输入的输出:

(
  [ 1, 'B', 'C' ],
  [ 2, 'C', 'H' ],
  [ 5, 'F', 'G' ]
)

使用示例

my @a1 = qw'A B C D E F';
my @a2 = qw'A C H D E G';

my $count = my @list = diff_array \@a1, \@a2;

print "There were $count differences\n\n";

for my $group (@list){
  my $index = shift @$group;
  print "  At index $index\n";
  print "    $_\n" for @$group;
  print "\n";
}

答案 5 :(得分:0)

你有正确的想法,但你只需要一个循环,因为你正在查看每个索引并比较数组之间的条目:

foreach my $a1 ( 0 .. $#array1) {
  if($array1[$a1] ne $array2[$a1]) {
     print "$a1: $array1[$a1] <-> $array2[$a1]\n";
   }
}