Как в Perl сравнить два массива объектов (логика сравнения закодирована в отдельной подпрограмме)?

Позвольте мне конкретизировать мою проблему, а не обобщать ее и сбивать с толку аудиторию. В моем коде у меня есть набор сетевых адресов (фактически членов объектной группы), хранящихся в отдельных массивах. Я хотел бы сравнить, является ли группа A подмножеством группы B.

Я использую модуль Net::IP для анализа IP-адресов и использую подпрограмму «перекрытия», чтобы определить, является ли элемент (может быть отдельным IP-адресом или подсетью) надмножеством другого элемента.

Проблема, с которой я сталкиваюсь, заключается в том, чтобы вернуть статус успеха, только если каждый элемент группы A принадлежит любому элементу группы B.

Вот как я подумал и продолжаю пытаться кодировать его аналогичным образом:

$status = "match";
foreach $ip (@group_a) {
  if a_in_b($ip,@group_b) #this sub-routine would be similar but with different comparison function
   {
   next;
   }
   else
   {
   $status = "no match"; 
   last;}
}

Пожалуйста, предложите мне, если есть лучший способ сделать это, хотел бы подобрать новые методы. Вышеупомянутая техника не выглядит звуковой вообще! Когда я искал некоторые решения, некоторые -for-equality">ссылки, кажется, предполагают, что я мог бы попробовать использовать оператор интеллектуального сопоставления и перегрузить его. Но перегрузка выходит за рамки моего уровня сложности в Perl, так что будьте добры, помогите!

РЕДАКТИРОВАТЬ: Обновлен мой код в соответствии с предложением. Вот рабочая версия (еще нужно добавить кусочки для отлова ошибок)

use Net::IP;
use strict;
use warnings;

my @subnet = ("10.1.128.0/24","10.1.129.0/24","10.1.130.0/24","10.1.108.4");
my @net = ("10.1.128.0/21","10.1.108.0/22");


sub array_subset {
    my ($x, $y) = @_;
    a_in_b ($_, @$y) or return '' foreach @$x;
    return 1;
};

sub a_in_b  {
  my $node1 = shift(@_);
  my @ip_list = @_;
  for my $node2 (@ip_list) {
    print $node2, "\n";
    my $ip1 = new Net::IP ($node1) || die;
    my $ip2 = new Net::IP ($node2) || die;
    print "$node1  $node2 \n";
    if ($ip1->overlaps($ip2)==$IP_A_IN_B_OVERLAP) {
      return 1;
    }

  }
  return "";
}

if (array_subset(\@subnet, \@net)) {
  print "Matches";
}else
{
  print "Doesn't match"
}

person Benny    schedule 14.05.2011    source источник
comment
Я хотел бы увидеть вашу подписку a_in_b.   -  person TLP    schedule 14.05.2011
comment
Структура блока кода аналогична... вместо a_in_b($ip,@group_b) в качестве оператора условия я буду использовать if ($ip1->overlaps($ip2)==$IP_A_IN_B_OVERLAP) в качестве условия if. Вы все еще хотите посмотреть на всю подпрограмму?   -  person Benny    schedule 14.05.2011
comment
Я пытаюсь понять, каковы ваши данные и как вы хотите их сравнить. Я не очень хорошо разбираюсь в IP и сетях, но знаю perl.   -  person TLP    schedule 14.05.2011
comment
Спасибо. На данный момент вы можете игнорировать тонкости IP-адресации, лучше посмотрите на модуль Net::IP, который выполняет всю логику. Функция overlaps сравнивает два элемента и возвращает значение ($ IP_A_IN_B_OVERLAP здесь является проверенным значением). Хотя модуль позволяет сравнивать один элемент с другим, я хочу сравнить один массив с другим массивом, возвращая значение true, только если все сравнения дали значение $IP_A_IN_B_OVERLAP. Надеюсь, это имеет смысл.   -  person Benny    schedule 14.05.2011
comment
Я не вижу способа обойти проверку каждого элемента массива по сравнению с другими. Не вникая в мельчайшие детали, вы не можете повлиять на сравнение. Насколько я понимаю, массивы умного сопоставления - это в основном текстовое совпадение. Если у вас есть большие массивы и/или сравнение требует времени, вы, вероятно, можете улучшить производительность с помощью некоторых трюков. Тогда, возможно, стоит попытаться объединить диапазоны и исключить значения, проанализировать данные и найти экстремальные значения и т. д.   -  person TLP    schedule 14.05.2011


Ответы (1)


Перегрузка ~~ немного излишняя. Я бы предложил использовать List::MoreUtils :

use List::MoreUtils qw/all/;
if (all { a_in_b($_, @bignet) } @smallnet) {
     # do something
};

Или просто перепишите свой собственный код в качестве подпрограммы и более извращенным способом:

sub array_subset {
    my ($x, $y) = @_;
    a_in_b ($_, @$y) or return '' foreach @$x;
    return 1;
};

# somewhere in the code 
if (array_subset(\@subnet, \@net)) {
    # do something
};
person Dallaylaen    schedule 14.05.2011
comment
Спасибо! Это почти сработало, но подводный камень был связан с моей логикой. Если у меня есть массив суперсетей (A,B) и подсетей (A1,A2,A3,B1), он не возвращает совпадений, потому что все 4 подсети не принадлежат одной и той же суперсети, что подтверждается логикой. Я хочу, чтобы он возвращал true для такого случая: A1,A2,A3 ⊆ A и B1 ⊆ B - person Benny; 15.05.2011
comment
@Бенни: А? Как я вижу, ваша логика (и, следовательно, моя) предполагает независимое тестирование каждого элемента подсети на всю суперсеть. - person Dallaylaen; 15.05.2011
comment
Ой, извините, похоже, мне нужно снова проверить свой код. Вернется с полным кодом. Большое спасибо за ваше время! - person Benny; 15.05.2011
comment
Я понял, что это был глупый неуместный оператор возврата. Я поместил его во внутренний блок вместо внешнего блока. Но теперь я застрял с ошибкой с модулем Net: IP, похоже, он не слаб с предоставленным IP-адресом. У меня нет контроля над источником данных, поэтому мне нужно знать, почему он не удался, и добавить соответствующий код проверки. Большое спасибо за вашу помощь! - person Benny; 15.05.2011