Подтвердить что ты не робот

Как вычесть массив из массива?

Когда я попробую следующее

#!/usr/bin/perl

use strict;
use warnings;
use Data::Dumper;

my @bl = qw(red green blue);
my @a = qw(green yellow purple blue pink);

print Dumper [grep {not @bl} @a];

Я получаю пустой массив. Я бы ожидал, что @bl вычитается из @a, поэтому выход был yellow purple pink.

Что здесь не так?

4b9b3361

Ответ 1

Вам нужно превратить @bl в хеш для выполнения заданной разницы:

my %in_bl = map {$_ => 1} @bl;
my @diff  = grep {not $in_bl{$_}} @a;

Ответ 2

См. perlfaq4: Как вычислить разницу в двух массивах?

В вашем коде not, вероятно, не делает то, что, по вашему мнению, делает.

not @bl всегда будет 1, если @bl - пустой массив, а undef, если @bl не пуст. Это не означает "элементы не в @bl" в любом смысле.

Ответ 3

@b1 оценивает значение true (это массив с ненулевым числом элементов), поэтому логический тест в вашей конструкции grep (not @b1) всегда будет возвращать false. grep фильтрует массив, возвращающий только те элементы, для которых логический тест возвращает true.

Вам нужно проверить, находится ли $_ (рассматриваемый элемент массива) в @bl или нет. Один из способов сделать это - создать временный хеш с помощью @bl в качестве ключей, а затем в вашей инструкции grep проверить наличие $_ в хэш-ключах:

#!/usr/bin/perl

use strict;
use warnings;
use Data::Dumper;

my @bl = qw(red green blue);
my @a = qw(green yellow purple blue pink);

# create a hash
my %h;

# nifty trick - use a hash slice to populate the
# hash. The values are irrelevant so we'll use @bl
# for those too
@h{@bl} = @bl;

print Dumper [grep {!exists $h{$_}} @a];

Ответ 4

Поскольку Perl 5.18.0 оператор smartmatch считается экспериментальным: Семейство функций smartmatch теперь является экспериментальным. Из-за этого я больше не буду использовать это решение.

Другой способ работы с оператором Smartmatch (если у вас есть perl-версия 5.010 или выше):

#!/usr/bin/env perl
use warnings;
use 5.012;

my @bl = qw(red green blue);
my @a = qw(green yellow purple blue pink);

my @s = grep{ not $_ ~~ @bl } @a;
say "@s"; # yellow purple pink

Ответ 5

Другая опция, использующая perl5i:

use perl5i::2;

my @bl = qw(red green blue);
my @a = qw(green yellow purple blue pink);
my @diff = @a->diff(\@bl);

say @diff->mo->perl;

Ответ 6

Другой способ, используя функцию minus из Acme:: Tools модуля CPAN:

use strict;
use warnings;
use Data::Dumper;
use Acme::Tools qw(minus);

my @bl = qw(red green blue);
my @a  = qw(green yellow purple blue pink);
my @diff = minus(\@a, \@bl);
print Dumper(\@diff);

__END__

$VAR1 = [
          'yellow',
          'purple',
          'pink'
        ];

Ответ 7

Другой способ:

List::Compare CPAN module
use List::Compare ;
...
my $compare_obj 
  = List::Compare->new(\@a , \@b1) ;
@diff = $compare_obj->get_Lonly() ;
...