Извините за поздний ответ, я полировал это некоторое время, потому что я не хотел еще один отрицательный результат (выводит меня из себя).
Это интересная проблема эффективности. Я не знаю, сработает ли мое решение для вас, но я подумала, что поделюсь им в любом случае. Вероятно, это эффективно, только если ваши массивы не меняются слишком часто, и если ваши массивы содержат много повторяющихся значений. Я не проводил никаких проверок эффективности.
По сути, решение состоит в том, чтобы удалить одно измерение перекрестной проверки, превратив значения массива в биты и выполнив побитовое сравнение всего массива за один раз. Значения массива дедуплицируются, сортируются и получают серийный номер. Массивы итоговых серийных номеров затем сохраняются в одном значении побитовым или. Таким образом, один массив может быть проверен на наличие одного серийного номера только с одной операцией, например ::10000
if ( array & serialno )
Для подготовки данных потребуется один прогон, который затем можно сохранить в кеше или аналогичном. Эти данные могут быть использованы до тех пор, пока ваши данные не изменятся (например, файлы / папки будут удалены или добавлены). Я добавил фатальный выход для неопределенных значений, что означает, что данные должны обновляться, когда это происходит.
Удачи!
use strict;
use warnings;
my @list1=('a', 'b', 'c');
my @list2=('a', 'b', 'f');
my @list3=('e', 'd', 'a');
my @list4=('f', 'g', 'h');
# combine arrays
my @total = (@list1, @list2, @list3, @list4);
# dedupe (Thanks Xetius for this code snippet)
my %unique = ();
foreach my $item (@total)
{
$unique{$item} ++;
}
# Default sort(), don't think it matters
@total = sort keys %unique;
# translate to serial numbers
my %serials = ();
for (my $num = 0; $num <= $#total; $num++)
{
$serials{$total[$num]} = $num;
}
# convert array values to serial numbers, and combine them
my @tx = ();
for my $entry (@list1) { $tx[0] |= 2**$serials{$entry}; }
for my $entry (@list2) { $tx[1] |= 2**$serials{$entry}; }
for my $entry (@list3) { $tx[2] |= 2**$serials{$entry}; }
for my $entry (@list4) { $tx[3] |= 2**$serials{$entry}; }
&print_all;
sub inList
{
my ($value, $list) = @_;
# Undefined serial numbers are not accepted
if (! defined ($serials{$value}) ) {
print "$value is not in the predefined list.\n";
exit;
}
return ( 2**$serials{$value} & $tx[$list] );
}
sub yesno
{
my ($value, $list) = @_;
return ( &inList($value, $list) ? "yes":"no" );
}
#
# The following code is for printing purposes only
#
sub print_all
{
printf "%-6s %-6s %-6s %-6s %-6s\n", "", "List1", "List2", "List3", "List4";
print "-" x 33, "\n";
&table_print(@list1);
&table_print(@list2);
&table_print(@list3);
&table_print(@list4);
}
sub table_print
{
my @list = @_;
for my $entry (@list) {
printf "%-6s %-6s %-6s %-6s %-6s\n", $entry,
&yesno($entry, 0),
&yesno($entry, 1),
&yesno($entry, 2),
&yesno($entry, 3);
}
print "-" x 33, "\n";
}