क्या पायथन एक सूची में कई मूल्यों की सदस्यता का परीक्षण कर सकता है?


121

मैं परीक्षण करना चाहता हूं कि किसी सूची में दो या अधिक मानों की सदस्यता है, लेकिन मुझे एक अप्रत्याशित परिणाम मिल रहा है:

>>> 'a','b' in ['b', 'a', 'foo', 'bar']
('a', True)

तो, क्या पायथन एक सूची में कई मूल्यों की सदस्यता का परीक्षण कर सकता है? उस परिणाम का क्या मतलब है?

जवाबों:


197

यह वही है जो आप चाहते हैं, और लगभग सभी मामलों में काम करेंगे:

>>> all(x in ['b', 'a', 'foo', 'bar'] for x in ['a', 'b'])
True

अभिव्यक्ति 'a','b' in ['b', 'a', 'foo', 'bar']अपेक्षा के अनुरूप काम नहीं करती है क्योंकि पायथन इसे टपल के रूप में व्याख्या करता है:

>>> 'a', 'b'
('a', 'b')
>>> 'a', 5 + 2
('a', 7)
>>> 'a', 'x' in 'xerxes'
('a', True)

अन्य विकल्प

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

>>> set(['a', 'b']).issubset(set(['a', 'b', 'foo', 'bar']))
True
>>> {'a', 'b'} <= {'a', 'b', 'foo', 'bar'}
True

...कभी कभी:

>>> {'a', ['b']} <= {'a', ['b'], 'foo', 'bar'}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

सेट केवल हैशिंग तत्वों के साथ बनाए जा सकते हैं। लेकिन जनरेटर की अभिव्यक्ति all(x in container for x in items)लगभग किसी भी कंटेनर प्रकार को संभाल सकती है। केवल आवश्यकता यह है कि containerपुन: चलने योग्य हो (अर्थात जनरेटर नहीं)। itemsकिसी भी पुनरावृत्ति हो सकती है।

>>> container = [['b'], 'a', 'foo', 'bar']
>>> items = (i for i in ('a', ['b']))
>>> all(x in [['b'], 'a', 'foo', 'bar'] for x in items)
True

स्पीड टेस्ट

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

चित्रण के लिए कुछ मानक यहां दिए गए हैं। सबसे बड़ा अंतर आ गया है जब दोनों containerऔर itemsअपेक्षाकृत छोटे हैं। उस स्थिति में, सबसेट का दृष्टिकोण परिमाण के एक क्रम के बारे में तेज़ी से होता है:

>>> smallset = set(range(10))
>>> smallsubset = set(range(5))
>>> %timeit smallset >= smallsubset
110 ns ± 0.702 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
>>> %timeit all(x in smallset for x in smallsubset)
951 ns ± 11.5 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

यह एक बड़े अंतर की तरह लग रहा है। लेकिन जब तक containerएक सेट है, तब allभी बड़े पैमाने पर पूरी तरह से प्रयोग करने योग्य है:

>>> bigset = set(range(100000))
>>> bigsubset = set(range(50000))
>>> %timeit bigset >= bigsubset
1.14 ms ± 13.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
>>> %timeit all(x in bigset for x in bigsubset)
5.96 ms ± 37 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

उप-परीक्षण का उपयोग करना अभी भी तेज है, लेकिन इस पैमाने पर केवल 5x के बारे में। पायथन के तेजी से cलागू होने के कारण गति को बढ़ावा मिला हैset , लेकिन दोनों मामलों में मौलिक एल्गोरिथ्म समान है।

यदि आपकी itemsसूची पहले से ही अन्य कारणों से एक सूची में संग्रहीत है, तो आपको सब्मिट टेस्ट दृष्टिकोण का उपयोग करने से पहले उन्हें एक सेट में बदलना होगा। फिर स्पीडअप लगभग 2.5x हो जाता है:

>>> %timeit bigset >= set(bigsubseq)
2.1 ms ± 49.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

और अगर आपका containerअनुक्रम है, और पहले परिवर्तित होने की आवश्यकता है, तो स्पीडअप और भी छोटा है:

>>> %timeit set(bigseq) >= set(bigsubseq)
4.36 ms ± 31.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

जब हम containerएक अनुक्रम के रूप में छोड़ते हैं तो केवल समय ही हमें विनाशकारी रूप से धीमा परिणाम देता है :

>>> %timeit all(x in bigseq for x in bigsubseq)
184 ms ± 994 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

और हां, हम केवल यही करेंगे कि अगर हमें ऐसा करना चाहिए। यदि सभी वस्तुएं bigseqहवादार हैं, तो हम इसकी बजाय करेंगे:

>>> %timeit bigset = set(bigseq); all(x in bigset for x in bigsubseq)
7.24 ms ± 78 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

यह विकल्प से सिर्फ 1.66x तेज है (set(bigseq) >= set(bigsubseq) , 4.36 से ऊपर)।

तो सबसेट परीक्षण आम तौर पर तेजी से होता है, लेकिन अविश्वसनीय अंतर से नहीं। दूसरी ओर, आइए देखें कि कब allतेज है। क्या होगा यदि itemsदस-मिलियन मान लंबे हैं, और उन मानों की संभावना है जो अंदर नहीं हैं container?

>>> %timeit hugeiter = (x * 10 for bss in [bigsubseq] * 2000 for x in bss); set(bigset) >= set(hugeiter)
13.1 s ± 167 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>> %timeit hugeiter = (x * 10 for bss in [bigsubseq] * 2000 for x in bss); all(x in bigset for x in hugeiter)
2.33 ms ± 65.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

जनरेटर को एक सेट में बदलना इस मामले में अविश्वसनीय रूप से बेकार हो जाता है। setनिर्माता पूरे जनरेटर का उपभोग करने के है। लेकिन शॉर्ट-सर्कुलेटिंग व्यवहार allयह सुनिश्चित करता है कि जनरेटर के केवल एक छोटे से हिस्से का उपभोग करने की आवश्यकता है, इसलिए यह परिमाण के चार आदेशों द्वारा सबसेट परीक्षण से तेज है ।

यह एक चरम उदाहरण है, माना जाता है। लेकिन जैसा कि यह दिखाता है, आप यह नहीं मान सकते कि एक दृष्टिकोण या दूसरा सभी मामलों में तेज होगा।

ऊपर का हिस्सा

अधिकांश समय, containerएक सेट में परिवर्तित करना इसके लायक है, कम से कम अगर इसके सभी तत्व उपलब्ध हैं। ऐसा इसलिए है क्योंकि inसेट के लिए O (1) है, जबकि inदृश्यों के लिए O (n) है।

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


62

इसे करने का दूसरा तरीका:

>>> set(['a','b']).issubset( ['b','a','foo','bar'] )
True

21
मजेदार तथ्य: set(['a', 'b']) <= set(['b','a','foo','bar'])एक ही चीज़ को जादू करने का एक और तरीका है, और "मैथिएर" दिखता है।
कर्क स्ट्रैसर

8
पाइथन 2.7 के रूप में आप उपयोग कर सकते हैं{'a', 'b'} <= {'b','a','foo','bar'}
विक्टर स्टिस्कला

11

मैं कर रहा हूँ यकीन है कि inअधिक से अधिक पूर्वता हो रही है ,तो अपने बयान में व्याख्या की जा रही है के रूप में 'a', ('b' in ['b' ...])है, जो तब का मूल्यांकन 'a', Trueके बाद से 'b'सरणी में है।

आप क्या चाहते हैं, कैसे करें, इसके लिए पिछला उत्तर देखें।


7

यदि आप अपने सभी इनपुट मैचों की जाँच करना चाहते हैं ,

>>> all(x in ['b', 'a', 'foo', 'bar'] for x in ['a', 'b'])

यदि आप कम से कम एक मैच देखना चाहते हैं ,

>>> any(x in ['b', 'a', 'foo', 'bar'] for x in ['a', 'b'])

3

पायथन पार्सर ने उस कथन का एक तुगलकी के रूप में मूल्यांकन किया, जहां पहला मूल्य था 'a', और दूसरा मूल्य अभिव्यक्ति है 'b' in ['b', 'a', 'foo', 'bar'](जो इसका मूल्यांकन करता है)True )।

आप एक साधारण कार्य लिख सकते हैं, जो आप चाहते हैं, हालांकि:

def all_in(candidates, sequence):
    for element in candidates:
        if element not in sequence:
            return False
    return True

और इसे कॉल करें:

>>> all_in(('a', 'b'), ['b', 'a', 'foo', 'bar'])
True

2
[x for x in ['a','b'] if x in ['b', 'a', 'foo', 'bar']]

मुझे लगता है कि इसका कारण यह है कि चुने हुए उत्तर की तुलना में बेहतर है कि आपको वास्तव में 'ऑल ()' फ़ंक्शन को कॉल करने की आवश्यकता नहीं है। खाली सूची, गलत कथन में गलत का मूल्यांकन करती है, गैर-खाली सूची सत्य का मूल्यांकन करती है।

if [x for x in ['a','b'] if x in ['b', 'a', 'foo', 'bar']]:
    ...Do something...

उदाहरण:

>>> [x for x in ['a','b'] if x in ['b', 'a', 'foo', 'bar']]
['a', 'b']
>>> [x for x in ['G','F'] if x in ['b', 'a', 'foo', 'bar']]
[]

1

मैं कहूंगा कि हम उन चौकोर कोष्ठकों को छोड़ भी सकते हैं।

array = ['b', 'a', 'foo', 'bar']
all([i in array for i in 'a', 'b'])

0

यहां प्रस्तुत दोनों उत्तर दोहराए गए तत्वों को नहीं संभालेंगे। उदाहरण के लिए, यदि आप परीक्षण कर रहे हैं कि क्या [१,२,२] [१,२,३,४] की एक सूची है, तो दोनों सत्य हो जाएंगे। हो सकता है कि आप क्या करना चाहते हैं, लेकिन मैं सिर्फ स्पष्ट करना चाहता था। यदि आप [1,2,3,4] में [1,2,2] के लिए गलत लौटना चाहते हैं, तो आपको दोनों सूचियों को क्रमबद्ध करना होगा और प्रत्येक सूची पर एक मूविंग इंडेक्स के साथ प्रत्येक आइटम की जांच करनी होगी। लूप के लिए बस थोड़ा अधिक जटिल है।


1
'दोनों'? दो से अधिक उत्तर हैं। क्या आपका मतलब है कि सभी उत्तर इस समस्या से ग्रस्त हैं, या केवल दो उत्तर (और यदि ऐसा है, तो कौन सा)?
विप्रकोज़न

-1

आप बिना लैम्बदास के पाइथोनिक कैसे हो सकते हैं! .. गंभीरता से नहीं लिया जाना चाहिए .. लेकिन यह तरीका भी काम करता है:

orig_array = [ ..... ]
test_array = [ ... ]

filter(lambda x:x in test_array, orig_array) == test_array

यदि आप किसी मान में हैं, तो अंत भाग को छोड़ दें यदि आप परीक्षण करना चाहते हैं:

filter(lambda x:x in test_array, orig_array)

1
बस एक सिर है कि यह पायथन 3 में जहां filterएक जनरेटर है इरादा के रूप में काम नहीं करेगा । listयदि आप वास्तव में ऐसा परिणाम प्राप्त करना चाहते हैं जिसे आप ==बूलियन संदर्भ में देख सकते हैं या (यह देखना है कि क्या यह खाली है) तो आपको इसे लपेटना होगा । एक सूची समझ या में एक जनरेटर अभिव्यक्ति का उपयोग करना anyया allबेहतर है।
20

-1

यहाँ है कि मैंने यह कैसे किया:

A = ['a','b','c']
B = ['c']
logic = [(x in B) for x in A]
if True in logic:
    do something
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.