2011-02-03 14 views
16

aşağıdakiBir dizi bir diziden nasıl çıkarılır?

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

boş bir dizi olsun çalıştığınızda. @bl'un @a'dan çıkarılmasını beklerdim, böylece çıktı yellow purple pink idi.

Burada sorun ne var?

+2

“çıkarma” doğru değil burada kelime. ** doğru kelimeyi bulduğunuzda, bir Pavlovian hash saldırısını tetikleyen bir tane olduğunu keşfedeceksiniz. – tchrist

cevap

33

Sen seti farkı gerçekleştirmek için bir karma haline @bl açmanız gerekir:

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

Bu soru, bu sorunun yanıtlama yanıtından daha iyidir - SSS, yalnızca iki dizi arasındaki "simetrik farkı" nasıl hesaplayacağınızı gösterir – mob

+1

@mob: Bu nedenle, önerilen bir güncellemeyle Brian'ı postalayın. – tchrist

+6

Perl 5.10 ya da daha yeni bir zamanda yazabilirim ki benim @ diff = grep {not $ _ ~~ @bl} @a; –

4

@b1 doğru olarak değerlendirilir senin grep içinde, yani Boole testi (o elementlerin sıfırdan farklı bir sayı ile bir dizi var) Yapı (not @b1) her zaman false değerini döndürür. grep, yalnızca boole testinin doğru döndüğü öğeleri döndüren bir diziyi filtreler.

$_ öğesinin (şu anda göz önünde bulundurulacak olan dizi öğesi) @bl içinde olup olmadığını görmek için sınamanız gerekir. Acme::Tools den minus işlevini kullanarak,

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

'% h' değerlerini doldurmak çok fazla. Eğer 'exists' kullanırsanız, '@h {@bl} =()' ile doldurmak sadece iyi ve muhtemelen daha hızlı olacaktır. –

1

Başka şekilde: Bunu yapmanın bir yolu, karma anahtarlarında $_ varlığı için grep beyanı kontrol altında, sonra tuşları olarak @bl kullanarak geçici karma üretmektir CPAN modülü: Başka bir seçenek perl5i kullanılarak

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

:

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

Perl 5.18.0'dan beri smartmatch operatörü deneysel olarak kabul edilir: The smartmatch family of features are now experimental. Bu yüzden bu çözümü artık daha fazla kullanamayacağım.

SmartMatch-operatörü ile bir başka yolu (eğer perl-version 5.010 veya daha varsa):

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

"O (n^2)" performansında bu sonuç elde edilemez, çünkü smartmatch işleci, @ a öğesindeki her öğe için her bir @ öğesinin karşısına denk gelir. – Floegipoky

+0

@Floegipoky: Yorumunuz benim için mantıklı geliyor. Perl 5 ile smartmatch operatörünü kullanmayı bıraktım. Cevabı ben düzenledim. –

-1

bir başka yolu kullanmaktır:

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