Как я могу сравнить массивы в Perl?

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

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

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

7
задан brian d foy 7 April 2010 в 17:31
поделиться

8 ответов

Прежде всего, ваши 2 массива должны быть написаны правильно.

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

Во-вторых, для произвольных массивов (например, массивов, элементы которых могут быть ссылками на другие структуры данных) вы можете использовать Data :: Compare .

Для массивов, элементы которых являются скалярными, вы можете выполнить сравнение, используя List :: MoreUtils попарно BLOCK ARRAY1 ARRAY2 , где BLOCK - ваша подпрограмма сравнения. Вы можете эмулировать попарно (если у вас нет доступа к 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 всегда может сортировать списки. Я не уверен, что он может делать попарные сравнения.

9
ответ дан 6 December 2019 в 07:25
поделиться

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

sub set{
  my %set = map { $_, undef }, @_;
  return sort keys %set;
}
sub compare{
    my ($listA,$listB) = @_;
    return ( (set(@$listA)-set(@$listB)) > 0)
}
1
ответ дан 6 December 2019 в 07:25
поделиться

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

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

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


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

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

4
ответ дан 6 December 2019 в 07:25
поделиться

Грубая сила должна помочь при малых a 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 элементов

0
ответ дан 6 December 2019 в 07:25
поделиться
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 или более поздняя версия, чтобы использовать оператор интеллектуального сопоставления ( ~~ ).

1
ответ дан 6 December 2019 в 07:25
поделиться

ИМХО, вы должны использовать List :: MoreUtils :: попарно . Однако, если по какой-то причине вы не можете этого сделать, следующая подпрограмма вернет 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 ];
}
0
ответ дан 6 December 2019 в 07:25
поделиться

List :: Compare

if ( scalar List::Compare->new(\@a, \@b)->get_intersection ) {
    …
}
7
ответ дан 6 December 2019 в 07:25
поделиться

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

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";
2
ответ дан 6 December 2019 в 07:25
поделиться
Другие вопросы по тегам:

Похожие вопросы: