2008-11-27 8 views
10

को देखते हुए:मैं एक पर्ल सरणी से तत्व कैसे जोड़ूं जो पहले से ही अन्य सरणी में नहीं हैं?

my @mylist1; 
push(@mylist1,"A"); 
push(@mylist1,"B"); 
push(@mylist1,"C"); 

my @mylist2; 
push(@mylist2,"A"); 
push(@mylist2,"D"); 
push(@mylist2,"E"); 

क्या पर्ल में तेज तरीका सभी तत्वों mylist1 में हैं और पहले से ही नहीं mylist2 में (ABCDE) mylist2 में डालने के लिए है।

उत्तर

12
my %k; 
map { $k{$_} = 1 } @mylist1; 
map { $k{$_} = 1 } @mylist2; 
@mylist2 = keys %k; 
वैकल्पिक रूप से

:

my %k; 
map { $k{$_} = 1 } @mylist2; 
push(@mylist2, grep { !exists $k{$_} } @mylist1); 

असल में - इन क्योंकि वे चाहे डुप्लिकेट मूल सूचियों में से किसी में मौजूद हो सकता है के लिए खाते में नहीं है गलत हो सकता है।

आपने अपने प्रश्न में यह नहीं कहा कि सूचियों को सेट का प्रतिनिधित्व करना है (जिसमें डुप्लिकेट नहीं हो सकते हैं) या केवल सादे सूचियां। आप प्रभावी रूप से @mylist2 = @mylist1 U @mylist2 चाहते हैं कि आप उन्हें सेट के रूप में पेश कर रहे हैं।

संपादित करें: बदल आवंटित करने के लिए वेतन वृद्धि -

+0

अगर आप मूल आदेश रखने के लिए की जरूरत नहीं है ठीक है। –

+1

दूसरा विकल्प मेरे माप के अनुसार सबसे तेज़ है - और सूची :: MoreUtils में uniq विधि से तेज़ है। –

2

[मूल जवाब "सवाल के बाद से" करने के लिए नीचे 2008/11/27 के रूप में हैश मान का रीड की बचत होती है; 2008-11-29 के रूप में वहां से विश्लेषण नया है।]

सबसे तेज़ - सुनिश्चित नहीं है। यह काम करता है, हालांकि यह बहुत नहीं है:

#!/bin/perl -w 
use strict; 

my @mylist1; 
push(@mylist1,"A"); 
push(@mylist1,"B"); 
push(@mylist1,"C"); 

my @mylist2; 
push(@mylist2,"A"); 
push(@mylist2,"D"); 
push(@mylist2,"E"); 

sub value_in 
{ 
    my($value, @array) = @_; 
    foreach my $element (@array) 
    { 
     return 1 if $value eq $element; 
    } 
    return 0; 
} 

@mylist2 = (@mylist2, grep { ! value_in($_, @mylist2) } @mylist1); 

print sort @mylist2, "\n"; 

इस हैश में सरणियों परिवर्तित करने से बचा जाता है - लेकिन बड़े सरणियों के लिए, value_in उप धीमा हो सकता है।

चूंकि सवाल "सबसे तेज़ तरीका क्या है", मैंने कुछ बेंचमार्किंग की। मेरे किसी भी आश्चर्यजनक आश्चर्य के लिए, मेरी विधि सबसे धीमी थी। कुछ हद तक मेरे आश्चर्य की बात है, सबसे तेज़ तरीका सूची :: MoreUtils से नहीं था। मेरे मूल प्रस्ताव के एक संशोधित संस्करण का उपयोग कर परीक्षण कोड और परिणाम यहां दिए गए हैं।

#!/bin/perl -w 
use strict; 
use List::MoreUtils qw(uniq); 
use Benchmark::Timer; 

my @mylist1; 
push(@mylist1,"A"); 
push(@mylist1,"B"); 
push(@mylist1,"C"); 

my @mylist2; 
push(@mylist2,"A"); 
push(@mylist2,"D"); 
push(@mylist2,"E"); 

sub value_in 
{ 
    my($value) = shift @_; 
    return grep { $value eq $_ } @_; 
} 

my @mylist3; 
my @mylist4; 
my @mylist5; 
my @mylist6; 

my $t = Benchmark::Timer->new(skip=>1); 
my $iterations = 10000; 

for my $i (1..$iterations) 
{ 
    $t->start('JLv2'); 
    @mylist3 = (@mylist2, grep { ! value_in($_, @mylist2) } @mylist1); 
    $t->stop('JLv2'); 
} 
print $t->report('JLv2'); 

for my $i (1..$iterations) 
{ 
    $t->start('LMU'); 
    @mylist4 = uniq(@mylist1, @mylist2); 
    $t->stop('LMU'); 
} 
print $t->report('LMU'); 

for my $i (1..$iterations) 
{ 
    @mylist5 = @mylist2; 
    $t->start('HV1'); 
    my %k; 
    map { $k{$_} = 1 } @mylist5; 
    push(@mylist5, grep { !exists $k{$_} } @mylist1); 
    $t->stop('HV1'); 
} 
print $t->report('HV1'); 

for my $i (1..$iterations) 
{ 
    $t->start('HV2'); 
    my %k; 
    map { $k{$_} = 1 } @mylist1; 
    map { $k{$_} = 1 } @mylist2; 
    @mylist6 = keys %k; 
    $t->stop('HV2'); 
} 
print $t->report('HV2'); 


print sort(@mylist3), "\n"; 
print sort(@mylist4), "\n"; 
print sort(@mylist5), "\n"; 
print sort(@mylist6), "\n"; 

Black JL: perl xxx.pl 
9999 trials of JLv2 (1.298s total), 129us/trial 
9999 trials of LMU (968.176ms total), 96us/trial 
9999 trials of HV1 (516.799ms total), 51us/trial 
9999 trials of HV2 (768.073ms total), 76us/trial 
ABCDE 
ABCDE 
ABCDE 
ABCDE 
Black JL: 

यह पर्ल 5.10.0 एक प्राचीन सूर्य E450 पर बहुलता के साथ 32-बिट स्पार्क के लिए संकलित सोलारिस 10

मुझे विश्वास है कि परीक्षण सेटअप निष्पक्ष हैं चल रहा है; वे सभी अपना जवाब एक नई सरणी में उत्पन्न करते हैं, मेरी सूची 1 और mylist2 से अलग (इसलिए मेरी सूची 1 और mylist2 को अगले परीक्षण के लिए पुन: उपयोग किया जा सकता है)। एचवी 1 (हैश मान 1) नामित उत्तर में @ mylist5 के असाइनमेंट के बाद समय शुरू हो गया है, जो मुझे लगता है कि सही है। हालांकि, जब मैं काम से पहले शुरुआत के साथ समय किया था, यह अभी भी सबसे तेज था:

Black JL: perl xxx.pl 
9999 trials of JLv2 (1.293s total), 129us/trial 
9999 trials of LMU (938.504ms total), 93us/trial 
9999 trials of HV1 (505.998ms total), 50us/trial 
9999 trials of HV2 (756.722ms total), 75us/trial 
ABCDE 
ABCDE 
ABCDE 
ABCDE 
9999 trials of HV1A (655.582ms total), 65us/trial 
Black JL: 
1
वजह से

अपने "(ABCDE)" टिप्पणी, मैं तुम्हें वास्तव में मतलब धक्का mylist2 में mylist1 उन तत्वों पर यह सोचते कर रहा हूँ जो मेरी सूची 1 में नहीं हैं। यदि यह धारणा गलत है, तो आपको कुछ कहना है कि आप किस क्रम में चीजों को समाप्त करना चाहते हैं।

सबसे पहले, हैश में mylist1 में कौन से तत्व हैं, स्टोर करें, फिर उन सभी को मेरी सूची में धक्का दें जो हैश में नहीं मिला mylist1।

my %in_mylist1; 
@in_mylist1{@mylist1} =(); 
push @mylist1, grep ! exists $in_mylist1{$_}, @mylist2; 
23

तुम सिर्फ इस्तेमाल कर सकते हैं List::MoreUtils मॉड्यूल के uniq:

use List::MoreUtils qw(uniq); 

my @mylist1; 
push(@mylist1, "A"); 
push(@mylist1, "B"); 
push(@mylist1, "C"); 

my @mylist2; 
push(@mylist2, "A"); 
push(@mylist2, "D"); 
push(@mylist2, "E"); 

@mylist2 = uniq(@mylist1, @mylist2); 

printf "%s\n", (join ',', @mylist2); # A,B,C,D,E 
+0

ठीक है, यह काम करेगा, लेकिन पर्ल सीखने का कोई तरीका नहीं है ... – Alnitak

+3

मॉड्यूल की पहचान और उपयोग करना सीखना perl सीखने का एक महत्वपूर्ण हिस्सा है। – oeuftete

+0

निश्चित रूप से, लेकिन आपको अभी भी बुनियादी बातों को जानना होगा – Alnitak

0
my(%work); 
@work{@mylist1, @mylist2} = undef; 
@mylist2 = sort keys %work; 
+0

यदि मेरी सूची 2 में डुप्लिकेट की अनुमति है (और मुझे कोई कारण नहीं दिखता है तो वे नहीं होंगे), तो यह समाधान उन्हें हटा देता है। – noswonky

संबंधित मुद्दे