Как я могу сравнить массивы в Perl? - PullRequest
7 голосов
/ 07 апреля 2010

У меня есть два массива, @a и @b. Я хочу сделать сравнение среди элементов двух массивов.

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

Если какой-либо элемент соответствует, тогда установите флаг. Есть ли простой способ сделать это?

Ответы [ 11 ]

9 голосов
/ 07 апреля 2010

Прежде всего, ваши 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 всегда может отсортировать списки. Я не уверен, что он может делать парные сравнения.

7 голосов
/ 07 апреля 2010

Список :: Сравнить

if ( scalar List::Compare->new(\@a, \@b)->get_intersection ) {
    …
}
4 голосов
/ 07 апреля 2010

Установите флажок, чтобы создать функцию пересечения, которая будет возвращать список элементов, присутствующих в обоих списках. Тогда ваше возвращаемое значение зависит от количества элементов в пересекающемся списке.

Вы можете легко найти в Интернете лучшую реализацию пересечения для Perl. Я помню, как искал его несколько лет назад.

Вот что я нашел:


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

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

2 голосов
/ 07 апреля 2010

Это один из способов:

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";
1 голос
/ 07 апреля 2010

Из требования, что «если любой элемент соответствует», используйте пересечение множеств:

sub set{
  my %set = map { $_, undef }, @_;
  return sort keys %set;
}
sub compare{
    my ($listA,$listB) = @_;
    return ( (set(@$listA)-set(@$listB)) > 0)
}
1 голос
/ 07 апреля 2010
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 или более поздней версии, чтобы использовать оператор умного совпадения (~~).

0 голосов
/ 03 октября 2018

Если вы считаете, что массивы с другим порядком различны, вы можете использовать Array :: Diff

if (Array::Diff->diff(\@a, \@b)->count) {
   # not_same
} else {
   # same
}
0 голосов
/ 19 сентября 2017
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
}
0 голосов
/ 14 сентября 2017

Это Perl. «Очевидное» решение:

my @a = qw"abc def efg ghy klm ghn";
my @b = qw"def ghy jgk lom com klm";
print "arrays equal\n"
    if @a == @b and join("\0", @a) eq join("\0", @b);

учитывая, что "\ 0" не находится в @ a.

Но спасибо, что подтвердили, что нет другого универсального решения, кроме своего собственного.

0 голосов
/ 07 апреля 2010

ИМХО, вы должны использовать List :: MoreUtils :: pairwise .Однако, если по какой-то причине вы не можете этого сделать, то следующий подпункт вернет 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 ];
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...