2012-01-06 5 views
7

मैं एक सूची समझ में एक मूल्य बनाना चाहता हूं, लेकिन उस मूल्य पर फ़िल्टर भी करना चाहता हूं। उदाहरण के लिए:किसी स्थिति का उपयोग करने के लिए पाइथन सूची समझ से लौटाए गए मूल्य को कैप्चर करना संभव है?

[expensive_function(x) for x in generator where expensive_function(x) < 5] 

मैं expensive_function यात्रा प्रति दो बार फोन करने से बचना चाहते हैं।

generator एक अनंत श्रृंखला वापस कर सकता है, और सूची की समझ का आलस्य मूल्यांकन नहीं किया जाता है। तो यह काम करेगा नहीं:

[y in [expensive_function(x) for x in generator where expensive_function(x)] where y < 5] 

मैं इस एक और तरीका लिख ​​सकता है, लेकिन यह सही एक सूची समझ के लिए लगता है और मुझे यकीन है कि यह एक आम उपयोग पैटर्न है कर रहा हूँ (संभव है या नहीं!)।

+0

क्या उत्तर में से कोई भी उत्तर स्वीकार करने योग्य है? यदि नहीं, तो आप अभी भी किस जानकारी की तलाश में हैं? –

+0

क्षमा करें इसे चिह्नित करने के लिए भूल गए। आपके उत्तर के लिए धन्यवाद! – Joe

+0

कोई समस्या नहीं है। उम्मीद कर रहा था कि आपको सिर्फ एक अनुस्मारक की आवश्यकता है। :) –

उत्तर

10

यदि generator असीमित हो सकता है, तो आप सूची समझ का उपयोग नहीं करना चाहते हैं। और सब कुछ एक लाइनर नहीं होना चाहिए।

def filtered_gen(gen): 
    for item in gen: 
     result = expensive_function(item) 
     if result < 5: 
      yield result 
+2

क्या 'आइटम' की अंतिम दो घटनाओं को' परिणाम 'से बदला जाना चाहिए? – Chris

+0

@ क्रिस: हाँ, धन्यवाद। –

+0

इसे +1 करें। आप itertools और जनरेटर अभिव्यक्तियों का उपयोग कर सकते हैं, लेकिन यह समझना बहुत आसान है। –

2

आप 2 जनरेटर भाव बनाना चाहिए:

ys_all = (expensive(x) for x in xs) 
ys_filtered = (y for y in ys_all if y <5) 

या

from itertools import imap, ifilter 
ys = ifilter(lambda y : y < 5, imap(expensive, xs)) 
+0

नहीं। यदि 'xs' अनंत नहीं है। अफसोस की बात है कि पाइथन में हास्केल सूची की समझ नहीं है। कुछ, कहीं, उड़ जाएगा। – Joe

+0

iterators – Simon

+0

के साथ अद्यतन उत्तर हाँ! मेरी राय में यह सबसे अच्छा जवाब है! क्या आप शायद उन्हें सूची समझ के बजाय "जेनरेटर समझ" कह सकते हैं? –

1

चेतावनी इसमें कुछ समय जटिल है, लेकिन काम करता है। मैं इसे समझाने के लिए एक उदाहरण का उपयोग करूंगा।

कहना expensive_function = math.sin

infinite generator = collections.count(0.1,0.1)

तो आपकी समस्या

करने पर निर्भर करता तो

[z for z in (y if y < 5 else next(iter([])) 
    for y in (math.sin(x) for x in itertools.count(0.1,0.1)))] 

[0.09983341664682815, 
0.19866933079506122, 
0.2955202066613396, 
0.3894183423086505, 
0.479425538604203] 

है चलो

चाल से next(iter([]))

यहाँ expensive_function एक जनरेटर और सुरुचिपूर्ण कुछ नहीं से एक StopIteration मजबूर करने के लिए केवल प्रति यात्रा एक बार कहा जाता है।

स्टॉप कंडीशन के साथ एक सीमित जेनरेटर के साथ अनंत जेनरेटर बढ़ाएं। जनरेटर raise StopIteration की अनुमति नहीं देगा, हम एक ठोस तरीके का चयन करते हैं i.e.next(iter([])) और अब आप एक परिमित जेनरेटर है, जो एक सूची समझ

में इस्तेमाल किया जा सकता के रूप में ओ पी गैर monotonic समारोह यहां के लिए उपरोक्त विधि के आवेदन के साथ संबंध था एक काल्पनिक गैर monotonic समारोह

है

महंगी गैर monotonic समारोह f(x) = random.randint(1,100)*x

बंद करो स्थिति = < 7

[z for z in (y if y < 7 else next(iter([])) for y in 
     (random.randint(1,10)*x for x in itertools.count(0.1,0.1)))] 

[0.9, 
0.6000000000000001, 
1.8000000000000003, 
4.0, 
0.5, 
6.0, 
4.8999999999999995, 
3.1999999999999997, 
3.5999999999999996, 
5.999999999999999] 

Btw: sin पूरी तरह से (0,2pi)

+0

पागल! यह काफी अलग है, क्योंकि 'पाप' एक गैर-मोनोटोनिक फ़ंक्शन है (मैंने यह नहीं कहा कि 'महंगा_फंक्शन' monotonic है, लेकिन यह है!) और यह रोकता है ** पहली बार ** स्थिति सत्य नहीं है, नहीं सभी शर्तों के लिए जारी ** ** जहां स्थिति सच है। उस ने कहा, यदि यह गैर-monotonic थे, तो इसके परिणामस्वरूप एक अनंत मूल्यांकन होगा ... – Joe

+0

@ जो, यह गैर-monotonic समारोह के लिए भी काम करेगा। मेरा अपडेट देखें – Abhijit

2

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

तो, आप इस प्रकार की सूची समझ है:

[expensive_function(x) for x in xrange(5) if expensive_function(x) % 2 == 0] 

और आप की गणना expensive_function दो बार जब वह अपने फिल्टर गुजरता बचना चाहते हैं। अधिक अर्थपूर्ण समझ वाक्य रचना के साथ बोली (स्काला, हास्केल, आदि) है जो आप की तरह बातें करते हैं की सुविधा देता है, तो आप बस गणना की समझ चर से भाव को नाम आवंटित करने की अनुमति निम्नलिखित:

# NOT REAL PYTHON 
[result for x in xrange(5) for result = expensive_function(x) if result % 2 == 0] 

लेकिन आप आसानी से इस बदल कर अनुकरण कर सकते हैं काम result = expensive_function(x) एक तत्व का एक क्रम पर एक और for यात्रा में:

[result for x in xrange(5) for result in (expensive_function(x),) if result % 2 == 0] 

और सबूत:

>>> def expensive_function(x): 
     print 'expensive_function({})'.format(x) 
     return x + 10 
>>> [expensive_function(x) for x in xrange(5) if expensive_function(x) % 2 == 0] 
expensive_function(0) 
expensive_function(0) 
expensive_function(1) 
expensive_function(2) 
expensive_function(2) 
expensive_function(3) 
expensive_function(4) 
expensive_function(4) 
[10, 12, 14] 
>>> [result for x in xrange(5) for result in (expensive_function(x),) if result % 2 == 0] 
expensive_function(0) 
expensive_function(1) 
expensive_function(2) 
expensive_function(3) 
expensive_function(4) 
[10, 12, 14] 
संबंधित मुद्दे

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