2009-04-06 16 views
20

मेरे पास संभावित मानों की एक सूची है:मैं कैसे सत्यापित कर सकता हूं कि पर्ल में सरणी (सूची) में कोई मान मौजूद है?

@a = qw(foo bar baz); 

मैं संक्षेप में कैसे जांचूं कि @a में कोई मान $val मौजूद है या अनुपस्थित है?

सूची में लूप करने के लिए एक स्पष्ट कार्यान्वयन है, लेकिन मुझे यकीन है कि TMTOWTDI


उत्तर देने वाले सभी के लिए धन्यवाद! मैं जिन तीन उत्तरों को हाइलाइट करना चाहता हूं वे हैं:

  1. स्वीकृत उत्तर - सबसे अधिक "अंतर्निर्मित" और पिछड़ा-संगत तरीका।

  2. RET's answer सबसे साफ है, लेकिन पर्ल 5.10 और बाद में केवल अच्छा है।

  3. draegtun's answer (संभवतः) थोड़ा तेज़ है, लेकिन अतिरिक्त मॉड्यूल का उपयोग करने की आवश्यकता है। मैं निर्भरताओं को जोड़ना पसंद नहीं करता अगर मैं उनसे बच सकता हूं, और इस मामले में प्रदर्शन अंतर की आवश्यकता नहीं है, लेकिन यदि आपके पास 1,000,000-तत्व सूची है तो आप इस उत्तर को आज़मा सकते हैं।

+1

मुझे यकीन है कि मैं सूची के साथ निर्भरता मुद्दे :: util को देखने नहीं कर रहा हूँ लागू। यह पर्ल के साथ मानक है और यदि आप इसे qw/first/(Draegtun के रूप में करते हैं) के साथ उपयोग करते हैं, तो आप केवल एक सबराउटिन आयात करते हैं। – Telemachus

+0

यह एक मुद्दा नहीं है, यह एक व्यक्तिगत वरीयता है। – MaxVT

+1

सूची :: उत्तर के साथ कोई निर्भरता मुद्दा नहीं है। अगर यह मैं था, तो यह स्वीकार्य जवाब होगा। कोर मॉड्यूल का उपयोग करने के लिए अविश्वसनीयता मुझे अंधविश्वास में निहित वरीयता के रूप में हमला करती है। इस मामले में grep {} लगभग उतना ही अच्छा है। – singingfish

उत्तर

20

पर्ल के bulit() फ़ंक्शन यह करने के लिए बनाया गया है।

@matches = grep(/^MyItem$/, @someArray); 

या आप पर्ल 5.10 है, तो आप मेल खाने वाला

@matches = grep($_ == $val, @a); 
+0

+1 अरे! सरल और अच्छा =) धन्यवाद – Viet

8

सूची :: MoreUtils 'any' फ़ंक्शन का उपयोग करने का एक संभावित तरीका है।

use List::MoreUtils qw/any/; 

my @array = qw(foo bar baz); 

print "Exist\n" if any {($_ eq "foo")} @array; 

अद्यतन: zoul की टिप्पणी के आधार पर ठीक किया।

+0

परिभाषित ("foo") हमेशा सत्य होता है, क्या आपका मतलब $ _ eq 'foo' था? – zoul

+0

-1 क्षमा करें, किस ज़ोल का उल्लेख किया गया है। –

+0

हाँ, या तो किसी भी {$ _ eq "foo"} या किसी भी {m/^ foo \ z /} ... – jettero

5

दिलचस्प समाधान, विशेष रूप से बार-बार खोज के लिए: ग्रेप में

my %hash; 
map { $hash{$_}++ } @a; 
print $hash{$val}; 
+0

हैश के बारे में ज़ोल का सुझाव इष्टतम के करीब है, हालांकि मैं सुझाव दूंगा कि जब आप अपने प्रोग्राम के दौरान अपने सरणी में मूल्य जोड़ते हैं और हटाते हैं तो अपने हैश में उन मानों को जोड़ें और हटा दें। –

+0

इसके अलावा, हालांकि यह काम करता है और आम है, कुछ लोग (स्वयं मुझे लगता है) एक शून्य संदर्भ में मानचित्र का उपयोग करने के बारे में शिकायत करेंगे। इसके बजाय @a के लिए $ हैश {$ _} ++ क्यों नहीं है? – jettero

+0

हां, यह अच्छा है। – zoul

38

में किसी भी अभिव्यक्ति सम्मिलित कर सकते हैं, smart-match operator ~~

print "Exist\n" if $var ~~ @array;

का उपयोग यह लगभग जादू है।

+0

एनबी। 5.10.1 से अर्थशास्त्र कुछ बदल गया है और इसे होना चाहिए: 'अगर $ var ~~ @ array'। ''~' के रूप में 'इन' के रूप में सोचने में मदद के लिए। रेफरी: http://perldoc.perl.org/perldelta.html#Smart-match-changes – draegtun

+0

धन्यवाद - तदनुसार ऑर्डर बदल दिया है। – RET

+1

मेरा perldoc यूआरएल अब मान्य नहीं है। यहां एक तय किया गया है: http://search.cpan.org/~dapm/perl-5.10.1/pod/perl5101delta.pod#Smart_match_changes – draegtun

2
$ perl -e '@a = qw(foo bar baz);$val="bar"; 
if (grep{$_ eq $val} @a) { 
    print "found" 
} else { 
    print "not found" 
}' 

$val='baq'; 

15

उपयोग जो पर्ल के साथ के रूप में मानक आता है List::Util से पहले समारोह नहीं मिला ....

use List::Util qw/first/; 

my @a = qw(foo bar baz); 
if (first { $_ eq 'bar' } @a) { say "Found bar!" } 

नायब पाया।पहले इसे प्राप्त करने वाले पहले तत्व को लौटाता है और इसलिए पूरी सूची के माध्यम से पुनरावृत्ति करने की आवश्यकता नहीं है (जो grep करेगा)।

+1

प्रति मूर्खब्रेट, यदि आयातित उप का उपयोग करते हैं, तो मैं सूची :: MoreUtil :: किसी भी() क्योंकि अवधारणा ("LIST में कोई भी आइटम मानदंड को पूरा करता है तो" एक वास्तविक मान देता है ") पहले से() (" पहला तत्व देता है जहां ब्लॉक से परिणाम एक वास्तविक मूल्य है) से पहले एक बेहतर मिलान होता है। ") – nohat

+0

सूची :: Util :: पहले() को कोर मॉड्यूल (यानी सर्वव्यापी) होने का लाभ है। अगर मैं सीपीएएन विकल्पों की तलाश में था तो मैं गंभीरता से पर्ल 6 :: जंक्शन :: किसी भी पर विचार करता हूं ... अगर (कोई भी (@ ए) ईक 'बाज') {} – draegtun

18

यह का जवाब "How can I tell whether a certain element is contained in a list or array?" पर उत्तर दिया गया है।

perlfaq को खोजने के लिए, आप अपने पसंदीदा ब्राउज़र का उपयोग कर perlfaq में सभी सवालों की सूची के माध्यम से खोज सकते हैं।

कमांड लाइन से, आप खोजशब्दों की खोज के लिए -q स्विच पर perldoc का उपयोग कर सकते हैं। आप "सूची" को खोजकर अपने जवाब मिल गया है जाएगा:

perldoc -q list 

सुनवाई शब्द "में" (इस जवाब ईसा सीगल और ब्रायन डी Foy के योगदान के हिस्से) एक संकेत है कि आपके डेटा को स्टोर करने के लिए शायद आपको हैश, सूची या सरणी का उपयोग नहीं करना चाहिए था। हैश को इस प्रश्न का उत्तर जल्दी और कुशलता से देने के लिए डिज़ाइन किया गया है। Arrays नहीं हैं।

कहा जा रहा है कि, इस दृष्टिकोण के कई तरीके हैं। Perl 5.10 में और बाद में, आप जांच करने के लिए है कि एक आइटम किसी सरणी या एक हैश में निहित है स्मार्ट मैच ऑपरेटर का उपयोग कर सकते हैं:

use 5.010; 

if($item ~~ @array) 
    { 
    say "The array contains $item" 
    } 

if($item ~~ %hash) 
    { 
    say "The hash contains $item" 
    } 
पर्ल के पिछले संस्करणों के साथ

, तो आप में कुछ अधिक परिश्रम करना होगा। आप इस क्वेरी मनमाना स्ट्रिंग मूल्यों में कई बार करने जा रहे हैं, तो सबसे तेज़ तरीका मूल सरणी को उलटने और एक हैश जिसका कुंजी पहली सरणी के मूल्यों हैं बनाए रखने के लिए शायद है:

@blues = qw/azure cerulean teal turquoise lapis-lazuli/; 
%is_blue =(); 
for (@blues) { $is_blue{$_} = 1 } 

अब आप चाहे $ जाँच कर सकते हैं is_blue {$ some_color}। ब्लूज़ को सभी जगहों पर हश में रखना एक अच्छा विचार हो सकता है।

यदि मान सभी छोटे पूर्णांक हैं, तो आप एक साधारण अनुक्रमित सरणी का उपयोग कर सकते हैं। एक सरणी इस तरह की कम जगह ले जाएगा:

@primes = (2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31); 
@is_tiny_prime =(); 
for (@primes) { $is_tiny_prime[$_] = 1 } 
# or simply @istiny_prime[@primes] = (1) x @primes; 

अब आप चाहे $ is_tiny_prime [$ some_number] की जाँच करें।

प्रश्न में मानों को स्ट्रिंग्स के बजाय पूर्णांक हैं, तो आप के बजाय बिट श्रृंखला का उपयोग करके काफी अंतरिक्ष के एक बहुत कुछ बचा सकते हैं:

@articles = (1..10, 150..2000, 2017); 
undef $read; 
for (@articles) { vec($read,$_,1) = 1 } 

अब यह देखना होगा कि vec ($ पढ़ते हैं, $ एन, 1) है कुछ $ एन के लिए सच है।

ये विधियां तेजी से व्यक्तिगत परीक्षण की गारंटी देती हैं लेकिन मूल सूची या सरणी के पुन: संगठन की आवश्यकता होती है। यदि आप एक ही सरणी के खिलाफ एकाधिक मानों का परीक्षण करना चाहते हैं तो वे केवल तभी भुगतान करते हैं।

यदि आप केवल एक बार परीक्षण कर रहे हैं, तो मानक मॉड्यूल सूची :: इस उद्देश्य के लिए पहले फ़ंक्शन का निर्यात करें। तत्व को पालने के बाद यह रोककर काम करता है। यह गति के लिए सी में लिखा है, और इसकी पर्ल बराबर इस सबरूटीन की तरह दिखता है:

sub first (&@) { 
    my $code = shift; 
    foreach (@_) { 
     return $_ if &{$code}(); 
    } 
    undef; 
} 

गति थोड़ा चिंता का विषय है, तो आम मुहावरा अदिश संदर्भ में ग्रेप (जो आइटम है कि इसकी हालत पारित कर दिया की संख्या देता है) का उपयोग करता है पूरी सूची को पार करने के लिए। हालांकि, आपको यह बताने का लाभ है कि यह कितने मैच मिले, हालांकि।

my $is_there = grep $_ eq $whatever, @array; 

यदि आप वास्तव में मिलान करने वाले तत्वों को निकालना चाहते हैं, तो बस सूची संदर्भ में grep का उपयोग करें।

my @matches = grep $_ eq $whatever, @array; 
1

आप अनावश्यक निर्भरता पसंद नहीं है, any या first खुद

sub first (&@) { 
    my $code = shift; 
    $code->() and return $_ foreach @_; 
    undef 
} 

sub any (&@) { 
    my $code = shift; 
    $code->() and return 1 foreach @_; 
    undef 
} 
संबंधित मुद्दे

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