2011-02-03 21 views
16

Kiedy próbuję następująceJak odjąć tablicę od tablicy?

#!/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]; 

dostaję pustą tablicę. Spodziewałbym się, że @bl został odjęty od @a, więc wynik wynosił yellow purple pink.

Co jest nie tak?

+2

„odjąć” nie jest właściwym słowo tutaj. Kiedy ** wyszukasz właściwe słowo, odkryjesz, że to on wywołuje atak hashowski. – tchrist

Odpowiedz

33

Musisz włączyć @bl do mieszania wykonać zadaną różnicę:

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

To jest lepsze niż odpowiedź na pytanie faq. Faq pokazuje tylko, jak obliczyć "symetryczną różnicę" pomiędzy dwiema tablicami: – mob

+1

@mob: Więc wyślij brian z sugerowaną aktualizacją. – tchrist

+6

W Perlu 5.10 lub nowszym można napisać: 'my @diff = grep {not $ _ ~~ @bl} @a;' –

4

@b1 wartość true (jest to tablica o niezerowej liczby elementów), więc logiczna Test w grep skonstruuj (not @b1) zawsze zwróci false. grep filtruje tablicę zwracającą tylko te elementy, dla których test boolowski zwraca wartość true.

Należy sprawdzić, czy $_ (aktualnie rozpatrywany element tablicy) jest w stanie @bl, czy też nie. Jednym ze sposobów, aby to zrobić, aby wygenerować tymczasowej hash używając @bl jako klucze, a następnie w grep czeku oświadczenie na obecność $_ w klawisze skrótu:

#!/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]; 
+1

Wypełnianie wartości '% h' jest przesadą. Jeśli użyjesz "exist", wypełnienie '@h {@bl} =()' będzie w porządku i prawdopodobnie szybciej. –

1

inny sposób, korzystając z funkcji minus z Acme::Tools moduł 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' 
     ]; 
2

Inną opcją korzystania 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; 
4

Od wersji Perl 5.18.0 operator smartmatch jest uważany za eksperymentalny: The smartmatch family of features are now experimental. Z tego powodu nie będę używać tego rozwiązania poniżej.

Innym sposobem z Smartmatch-operatora (jeśli masz Perl w wersji 5.010 lub nowszej):

#!/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 
+0

Czy nie spowoduje to wydajności 'O (n^2)', ponieważ operator smartmatch dopasowuje się do każdego elementu '@ bl' dla każdego elementu w' @ a'? – Floegipoky

+0

@Floegipoky: Twój komentarz brzmi dla mnie rozsądnie. W Perlu 5 przestałem używać operatora smartmatch. Edytowałem odpowiedź. –

-1

Innym sposobem jest użycie:

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