पहले तत्व को उस क्रम में खोजें जो एक विधेय से मेल खाता है


171

मैं एक सूची में पहला तत्व ढूंढना चाहता हूं जो एक विधेय से मेल खाता हो।

वर्तमान कोड काफी बदसूरत है:

[x for x in seq if predicate(x)][0]

मैंने इसे बदलने के बारे में सोचा है:

from itertools import dropwhile
dropwhile(lambda x: not predicate(x), seq).next()

लेकिन कुछ और अधिक सुरुचिपूर्ण होना चाहिए ... और यह अच्छा होगा Noneयदि कोई मैच नहीं मिला है तो एक अपवाद को बढ़ाने के बजाय एक मूल्य लौटाता है।

मुझे पता है कि मैं सिर्फ एक फ़ंक्शन को परिभाषित कर सकता हूं:

def get_first(predicate, seq):
    for i in seq:
        if predicate(i): return i
    return None

लेकिन इस तरह से उपयोगिता कार्यों के साथ कोड भरना शुरू करना काफी बेस्वाद है (और लोग शायद ध्यान नहीं देंगे कि वे पहले से ही वहां हैं, इसलिए वे समय के साथ दोहराए जाते हैं) अगर वहाँ पहले से ही प्रदान करने वाले इंस निर्मित किए जाते हैं।


3
" पायथन सीक्वेंस फंक्शन फंक्शन " की तुलना में बाद में पूछे जाने के अलावा , इस सवाल का बहुत बेहतर शीर्षक है
वुल्फ

जवाबों:


250

किसी अनुक्रम seqसे मेल खाता पहला तत्व खोजने के लिए predicate:

next(x for x in seq if predicate(x))

या ( itertools.ifilterपायथन 2 पर) :

next(filter(predicate, seq))

यह उठता है StopIterationअगर कोई नहीं है।


Noneयदि ऐसा कोई तत्व नहीं है तो वापस लौटने के लिए :

next((x for x in seq if predicate(x)), None)

या:

next(filter(predicate, seq), None)

28
या आप दूसरे "डिफ़ॉल्ट" तर्क की आपूर्ति कर सकते हैं nextजिसका उपयोग अपवाद को बढ़ाने के बजाय किया जाता है।
कार्ल केनचेल

2
@fortran: next()पायथन 2.6 के बाद से उपलब्ध है। आप नई विशेषताओं के साथ खुद को जल्दी से परिचित करने के लिए व्हाट्स न्यू पेज पढ़ सकते हैं ।
jfs

1
मैं एक अजगर नौसिखिया हूं और डॉक्स पढ़ता हूं और इफिल्टर "उपज" विधि का उपयोग करता है। मुझे लगता है कि इसका मतलब यह है कि विधेय का आलसी मूल्यांकन किया जाता है जैसे हम जाते हैं। यानी, हम पूरी सूची के माध्यम से विधेय को नहीं चलाते हैं क्योंकि मेरे पास एक विधेय कार्य है जो थोड़ा महंगा है और मैं उस बिंदु तक केवल पुनरावृति करना चाहता हूं जहां हम एक आइटम पाते हैं
कन्नन एकनाथ

2
@geekazoid: seq.find(&method(:predicate))या के लिए उदाहरण के तरीकों जैसे और भी अधिक संक्षिप्त:[1,1,4].find(&:even?)
JFS

16
ifilterका नाम बदलकर filterअजगर 3 रखा गया
tsauerwein

92

आप एक डिफ़ॉल्ट मान के साथ एक जनरेटर अभिव्यक्ति का उपयोग कर सकते हैं और फिर nextयह:

next((x for x in seq if predicate(x)), None)

हालांकि इस वन-लाइनर के लिए आपको पायथन> = 2.6 का उपयोग करना होगा।

यह बल्कि लोकप्रिय लेख आगे इस मुद्दे पर चर्चा करता है: सबसे स्वच्छ पायथन सूची में फ़ंक्शन?


8

मुझे नहीं लगता कि आपके प्रश्न में प्रस्तावित समाधानों के साथ कुछ भी गलत है।

अपने स्वयं के कोड में, मैं इसे इस तरह लागू करूंगा:

(x for x in seq if predicate(x)).next()

के साथ वाक्य रचना ()एक जनरेटर बनाता है, जो एक साथ सभी सूची बनाने से अधिक कुशल है []


और केवल इतना ही नहीं - []अगर आप कभी भी समस्याएं खत्म कर सकते हैं, तो अगर यह कभी खत्म नहीं होता है या इसके तत्वों को बनाना मुश्किल है, तो बाद में इसे प्राप्त होता है ...
glglgl

6
'generator' object has no attribute 'next'पायथन 3. पर
jfs

@glglgl - जैसा कि पहले बिंदु के लिए (कभी समाप्त नहीं होता) मुझे संदेह है, क्योंकि तर्क एक परिमित अनुक्रम है [अधिक सटीक रूप से ओपी के प्रश्न के अनुसार एक सूची]। दूसरे के लिए के रूप में: फिर से, चूंकि आपूर्ति की गई तर्क एक अनुक्रम है, वस्तुओं को पहले से ही बनाया जाना चाहिए और संग्रहीत किया जाना चाहिए जब तक यह फ़ंक्शन कहा जाता है .... या क्या मैं कुछ याद कर रहा हूं?
मैक

@JFSebastian - धन्यवाद, मुझे इस बारे में जानकारी नहीं थी! :) जिज्ञासा से बाहर, इस पसंद के पीछे डिजाइन सिद्धांत क्या है?
मैक

@ एमएसी - अन्य विशेष विधियों के डबल अंडरस्कोर के साथ स्थिरता के लिए। देखें python.org/dev/peps/pep-3114
च्युई

1

जेएफ सेबेस्टियन का जवाब सबसे सुरुचिपूर्ण है, लेकिन पाइथन 2.6 की आवश्यकता होती है, जैसा कि फोरट्रान ने बताया था।

पायथन संस्करण <2.6 के लिए, यहाँ सबसे अच्छा मैं आ सकता है:

from itertools import repeat,ifilter,chain
chain(ifilter(predicate,seq),repeat(None)).next()

वैकल्पिक रूप से यदि आपको बाद में एक सूची की आवश्यकता थी (सूची StopIteration को संभालती है), या आपको पहले की तुलना में अधिक आवश्यकता थी, लेकिन फिर भी सभी नहीं, तो आप इसे आइलिस के साथ कर सकते हैं:

from itertools import islice,ifilter
list(islice(ifilter(predicate,seq),1))

अद्यतन: हालांकि, मैं व्यक्तिगत रूप से पहले से कहे गए पूर्वनिर्धारित फ़ंक्शन का उपयोग कर रहा हूं (जो कि StopIteration को पकड़ता है और कोई नहीं लौटाता। यहां उपरोक्त उदाहरण पर एक संभावित सुधार है: फ़िल्टर / ifilter का उपयोग करने से बचें:

from itertools import islice,chain
chain((x for x in seq if predicate(x)),repeat(None)).next()

11
ओह! अगर यह नीचे आता है, तो मैं बस "अगर" इसके अंदर "अगर" के साथ "लूप" के लिए सरल करूंगा - पढ़ने में बहुत आसान
निक पर्किन्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.