Как удалить элементы массива, равные некоторому элементу, во втором массиве в Perl - PullRequest
11 голосов
/ 23 сентября 2011

Просто интересно, если мне даны два массива, A и B, как удалить / удалить те элементы в A, которые также можно найти в B? Какой самый эффективный способ сделать это?

А также, как особый случай, если B - это результирующий массив после grep на A, как это сделать? Конечно, в этом случае мы можем сделать grep в отрицательном состоянии. Но есть ли что-то вроде взятия дополнения массива относительно другого в perl?

Спасибо.

Ответы [ 6 ]

7 голосов
/ 23 сентября 2011

Каждый раз, когда вы думаете о found in, вы, вероятно, ищете хеш.В этом случае вы должны создать хэш ваших значений B.Затем вы должны выполнить grep A, проверяя хэш для каждого элемента.

my @A = 1..9;
my @B = (2, 4, 6, 8);
my %B = map {$_ => 1} @B;

say join ' ' => grep {not $B{$_}} @A; # 1 3 5 7 9

Как видите, perl обычно не поддерживает какую-либо таблицу found in сама по себе, поэтому вы должны предоставить ее.Приведенный выше код может быть легко заключен в функцию, но для эффективности его лучше всего делать встроенным.

3 голосов
/ 23 сентября 2011

Посмотрите на методы none, all, part, notall, доступные через List :: MoreUtils . Вы можете выполнить практически любую операцию над множеством, используя методы, доступные в этом модуле.

На Perl Training Australia

есть хорошее руководство.
1 голос
/ 23 сентября 2011

Если вы попросите наиболее эффективный способ:

my @A = 1..9;
my @B = (2, 4, 6, 8);

my %x;
@x{@B} = ();
my @AminusB = grep !exists $x{$_}, @A;

Но вы заметите разницу между моим и Эриком Стромом решение только для больших входов.

Вам может пригодиться этот функциональный подход:

sub complementer {
  my %x;
  @x{@_} = ();
  return sub { grep !exists $x{$_}, @_ };
}

my $c = complementer(2, 4, 6, 8);

print join(',', $c->(@$_)), "\n" for [1..9], [2..10], ...;

# you can use it directly of course
print join(' ', complementer(qw(a c e g))->('a'..'h')), "\n";
0 голосов
/ 23 сентября 2011

Опять же, вам лучше использовать хеш, но вы также можете использовать Perl6 :: Junction . Снова воровство Эрика Строма пример,

use Perl6::Junction qw(none);

my @A = 1..9;
my @B = (2, 4, 6, 8);

say join ' ' => grep {none(@B) == $_} @A; # 1 3 5 7 9
0 голосов
/ 23 сентября 2011

Возможно, вам лучше использовать хеш, но вы также можете использовать smart match Кража Пример Эрика Строма ,

my @A = 1..9;
my @B = (2, 4, 6, 8);

say join ' ' => grep {not $_ ~~ @B } @A; # 1 3 5 7 9
0 голосов
/ 23 сентября 2011

Как уже упоминалось Эрик Стром , всякий раз, когда вам нужно найти что-то конкретное, всегда проще, если у вас есть хеш.

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

# Create a B Hash

my %BHash;
foreach my $element (@B) {
   $BHash{$element} = 1;
}

# Go through @A element by element and delete duplicates

my $index = 0;
foreach my $element (@A) {
   if (exists $BHash{$element}) { 
      splice @A, $index, 1;    #Deletes $A[$index]
      $index = $index + 1;
   }
}

В первом цикле мы просто создаем хэш, ключ которого задается элементами в @B.

Во втором цикле мы проходим каждый элемент в @A, сохраняя при этом индекс в @A.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...