如何比较Perl中的数组?

时间:2010-04-07 10:51:26

标签: perl arrays

我有两个数组,@a@b。我想对两个数组的元素进行比较。

my @a = qw"abc def efg ghy klm ghn";
my @b = qw"def ghy jgk lom com klm";

如果任何元素匹配,则设置一个标志。有没有简单的方法呢?

12 个答案:

答案 0 :(得分:9)

首先,需要正确编写2个数组。

@a = ("abc","def","efg","ghy","klm","ghn");
@b = ("def","efg","ghy","klm","ghn","klm");

其次,对于任意数组(例如,其元素可能引用其他数据结构的数组),您可以使用Data::Compare

对于元素为标量的数组,可以使用List::MoreUtils pairwise BLOCK ARRAY1 ARRAY2进行比较,其中BLOCK是您的比较子例程。您可以通过以下方式模拟pairwise(如果您没有List :: MoreUtils访问权限):

if (@a != @b) {
    $equals = 0;
} else {
    $equals = 1;
    foreach (my $i = 0; $i < @a; $i++) {
        # Ideally, check for undef/value comparison here as well 
        if ($a[$i] != $b[$i]) { # use "ne" if elements are strings, not numbers
                                # Or you can use generic sub comparing 2 values
            $equals = 0;
            last;
        }
    }
}

P.S。我不确定,但List::Compare可能总是对列表进行排序。我不确定它是否可以进行成对比较。

答案 1 :(得分:7)

List::Compare

if ( scalar List::Compare->new(\@a, \@b)->get_intersection ) {
    …
}

答案 2 :(得分:4)

选中以创建交叉函数,该函数将返回两个列表中存在的项目列表。然后,您的返回值取决于相交列表中的项目数。

您可以在网上轻松找到有关Perl的最佳实现。我记得几年前找它。

这是我发现的:


my @array1 = (1, 2, 3);
my @array2 = (2, 3, 4);
my %original = ();
my @isect = ();

map { $original{$_} = 1 } @array1;
@isect = grep { $original{$_} } @array2;

答案 3 :(得分:2)

这是一种方式:

use warnings;
use strict;
my @a = split /,/, "abc,def,efg,ghy,klm,ghn";
my @b = split /,/, "def,ghy,jgk,lom,com,klm";
my $flag = 0;
my %a;
@a{@a} = (1) x @a;
for (@b) {
    if ($a{$_}) {
        $flag = 1;
        last;
    }
}
print "$flag\n";

答案 4 :(得分:1)

my @a = qw' abc def efg ghy klm ghn ';
my @b = qw' def ghy jgk lom com klm ';

my $flag;

foreach  my $item(@a) {
  $flag = @b~~$item ? 0 : 1;
  last if !$flag;
}

请注意,您需要使用Perl 5.10或更高版本才能使用smart match operator~~)。

答案 5 :(得分:1)

根据'if 任何元素匹配'的要求,使用集合的交集:

sub set{
  my %set = map { $_, undef }, @_;
  return sort keys %set;
}
sub compare{
    my ($listA,$listB) = @_;
    return ( (set(@$listA)-set(@$listB)) > 0)
}

答案 6 :(得分:0)

蛮力应该为小n

做诀窍
my $flag = 0;
foreach my $i (@a) {
    foreach my $k (@b) {
        if ($i eq $k) {
            $flag = 1;
            last;
        }
    }
}

对于大型n,请使用哈希表:

my $flag   = 0;
my %aa     = ();
   $aa{$_} = 1 foreach (@a);
foreach my $i (@b) {
    if ($aa{$i}) {
        $flag = 1;
        last;
    }
}

n|@a| + |@b| > ~1000个项目

答案 7 :(得分:0)

恕我直言,你应该使用List::MoreUtils::pairwise。但是,如果由于某种原因你不能,那么下面的sub将为每个索引返回1,其中第一个数组中的值比较等于第二个数组中的值。您可以根据需要概括此方法,并根据需要传递自己的比较器,但此时,只需安装List::MoreUtils就可以更有效地利用您的时间。

use strict; use warnings;

my @a = qw(abc def ghi jkl);
my @b = qw(abc dgh dlkfj jkl kjj lkm);
my $map = which_ones_equal(\@a, \@b);

print join(', ', @$map), "\n";

sub which_ones_equal {
    my ($x, $y, $compare) = @_;
    my $last = $#$x > $#$y ? $#$x : $#$y;
    no warnings 'uninitialized';
    return [ map { 0 + ($x->[$_] eq $y->[$_]) } $[ .. $last ];
}

答案 8 :(得分:0)

这是Perl。显而易见的&#39;溶液:

 <?php
      $sql2 = "SELECT * FROM smf_log_digest WHERE note_type = 'topic'";
      $result2 = $conn->query($sql2);
      if ($result2->num_rows > 0) {
        while($row2 = $result2->fetch_assoc()) {
          $number = $row2["id_msg"];
          $sql3 = "SELECT * FROM smf_messages WHERE id_msg = $number LIMIT 10";
          $result3 = $conn->query($sql3);
          if ($result3->num_rows > 0) {
            while($row3 = $result3->fetch_assoc()) {
              echo $row3["subject"];
            }
          } else {
            echo "";
          }
        }
      } else {
        echo "";
      }
      $conn->close();
    ?>

给出&#34; \ 0&#34;不在@a。

但是,感谢您确认没有其他通用解决方案,而不是滚动自己的解决方案。

答案 9 :(得分:0)

my @a1 = qw|a b c d|;
my @a2 = qw|b c d e|;

for my $i (0..$#a1) {
    say "element $i of array 1 was not found in array 2" 
        unless grep {$_ eq $a1[$i]} @a2
}

答案 10 :(得分:0)

如果您认为具有不同顺序的数组是不同的,则可以使用Array::Diff

if (Array::Diff->diff(\@a, \@b)->count) {
   # not_same
} else {
   # same
}

答案 11 :(得分:0)

这个问题可能还意味着两件事,即“如果有任何元素匹配,则设置一个标志”:

  1. 元素处于相同位置,即$ a [2] eq $ b [2]
  2. 任意位置的值,即$ a [3] eq $ b [5]

对于情况1,您可以这样做:

# iterate over all positions, and compare values at that position
my @matches = grep { $a[$_] eq $b[$_] } 0 .. $#a;

# set flag if there's any match at the same position 
my $flag = 1 if @matches;

对于情况2,您可以这样做:

# make a hash of @a and check if any @b are in there
my %a = map { $_ => 1 } @a;
my @matches = grep { $a{$_} } @b;

# set flag if there's matches at any position 
my $flag = 1 if @matches;

请注意,在第一种情况下,@matches保留存在匹配元素的索引,在第二种情况下,@ matches保留匹配值在它们出现在@b中的顺序。