0

我有一个二维数组:

array[0][0]=1
array[0][1]=2
array[0][2]=4
array[1][0]=0
array[1][1]=2

我想检查 array[0][$i] 和 array[1][$j] 之间的至少一个元素是否相同。我想了很长的路要走,因为

for my $i (0..($#{$array[0]}+1)){
    for my $j(0..($#{$array[1]}+1)){
      if (array[0][$i]==array[1][$j]){
          say "There is a match";
      }
    }
 }

有没有可能找到更好的方法?如果我有一个更大的数组,有没有办法在两个数组共享至少一个元素时停止循环?

4

3 回答 3

3

您可以使用intersectfrom Array::Utils来查找两个子数组的交集。如果结果列表为空,则没有公共元素。

#!/usr/bin/perl

use strict;
use warnings;
use feature 'say';

use Array::Utils qw(intersect);

my @array = (
    [ 1, 2, 4 ],
    [ 0, 2 ]
);  

say "There is a match" if intersect(@{$array[0]}, @{$array[1]});

如果您想计算匹配数,只需intersect在标量上下文中调用:

my $count = intersect(@{$array[0]}, @{$array[1]});

关于性能的注意事项:我运行了一个基准测试,将我的答案与使用List::MoreUtils的 amon 解决方案进行比较,并将水吹出几个数量级。这并不是一个巨大的惊喜,因为它会做完全不同的事情:一旦找到一个匹配项就停止,同时找到每个匹配项。如果你只关心匹配是否存在,我肯定会推荐这种方法,因为它对于任何非平凡的数据集都会明显更快。仅当您想要匹配列表时才有用。anyintersectanyintersectanyintersectanyintersect

于 2013-08-21T14:25:01.443 回答
3

您可以跳出(标记的)循环。请注意,您的代码是错误的,因为数组是从零开始索引的。你想从 to 循环0$#array而不是从1to$#array + 1循环scalar @array(除非你摆弄某些变量)。

my $found_same = 0;
my ($x, $y) = @array[0, 1];  # $x, $y are arrayrefs we want to loop over
my ($x_i, $y_i);

INDEX:
for $x_i (0 .. $#$x) {
  for $y_i (0 .. $#$y) {
    if ($x->[$x_i] == $y->[$y_i]) {
      $found_same = 1;
      last INDEX;
    }
  }
}

say "found same value $x->[$x_i] at indices $x_i, $y_i" if $found_same;

如果您对索引不感兴趣,仅在存在相同值的情况下,您应该遍历这些值:

my $found_same = 0;
my ($x, $y) = @array[0, 1];
INDEX:
for my $x_val (@$x) {
  for my $y_val (@$y) {
    if ($x_val = $y_val) {
      $found_same = 1;
      last INDEX;
    }
  }
}

say "found some same value" if $found_same;

如果我们把它写成一个函数,我们可以去掉丑陋的变量重新赋值,并且可以return打破循环:

my $find_same = sub {
  my ($x, $y) = @_;
  for my $x_val (@$x) {
    for my $y_val (@$y) {
      return 1 if $x_val == $y_val;
    }
  }
  return 0;
};

say "found some same value" if $find_same->(@array[0, 1]);

在 的帮助下List::MoreUtils,有一个很短的方法可以写这个:

use List::MoreUtils 'any';

my ($x, $y) = @array[0, 1];
say "found some same value" if any { my $val = $_; any { $val == $_ } @$y } @$x;

所有这些解决方案都假设您只有数字数据。

于 2013-08-21T14:26:03.767 回答
0

此代码可能回答了不同的问题。这将检查相同的值是否在数组中的任何位置出现两次。

哈希有助于检查一个值是否已经被看到。这里的两个代码块都使用数组中的值作为哈希键。下面的第一个代码计算一个数组值被看到的次数,并在它超过一个时报告。第二个块保存看到值的位置的索引,因此它可以报告找到值的两对索引。

my %values;
INDEX:
for my $ii (0 .. $#array) {
    for my $jj ( 0..($#{$array[$ii]})){
        my $val = $array[$ii][$jj];
        if ( ++$values{$val} > 1 ) {
            say "found same value $val at indices $ii, $jj";
            last INDEX;
        }
    }
}

my %indices;
INDEX:
for my $ii (0 .. $#array) {
    for my $jj ( 0..($#{$array[$ii]})){
        my $val = $array[$ii][$jj];
        if ( defined $indices{$val} ) {
            say "found same value $val at indices $indices{$val} and at $ii, $jj";
            last INDEX;
        }
        $indices{$val} = "$ii, $jj";
    }
}
于 2013-08-21T14:50:17.933 回答