У меня есть два массива, @a
и @b
. Я хочу сделать сравнивание среди элементов двух массивов.
my @a = qw"abc def efg ghy klm ghn";
my @b = qw"def ghy jgk lom com klm";
Если какие-либо соответствия элемента затем устанавливают флаг. Там какой-либо простой путь состоит в том, чтобы сделать это?
Прежде всего, ваши 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 всегда может сортировать списки. Я не уверен, что он может делать попарные сравнения.
Из требования, что «если любой элемент соответствует», используйте пересечение наборов:
sub set{
my %set = map { $_, undef }, @_;
return sort keys %set;
}
sub compare{
my ($listA,$listB) = @_;
return ( (set(@$listA)-set(@$listB)) > 0)
}
Установите этот флажок, чтобы создать функцию пересечения, которая будет возвращать список элементов, присутствующих в обоих списках. Тогда ваше возвращаемое значение зависит от количества элементов в пересеченном списке.
Вы можете легко найти в Интернете лучшую реализацию Intersect для Perl. Я помню, как искал его несколько лет назад.
Вот что я нашел:
my @array1 = (1, 2, 3); my @array2 = (2, 3, 4); my %original = (); my @isect = (); map { $original{$_} = 1 } @array1; @isect = grep { $original{$_} } @array2;
Грубая сила должна помочь при малых 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
элементов
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 или более поздняя версия, чтобы использовать оператор интеллектуального сопоставления ( ~~
).
ИМХО, вы должны использовать 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 ];
}
if ( scalar List::Compare->new(\@a, \@b)->get_intersection ) {
…
}
Это один из способов:
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";