पायथन में दो जनरेटर कैसे जुड़ें?


187

मैं निम्नलिखित कोड बदलना चाहता हूं

for directory, dirs, files in os.walk(directory_1):
    do_something()

for directory, dirs, files in os.walk(directory_2):
    do_something()

इस कोड के लिए:

for directory, dirs, files in os.walk(directory_1) + os.walk(directory_2):
    do_something()

मुझे त्रुटि मिली:

असमर्थित ऑपरेंड प्रकार (ओं) के लिए +: 'जनरेटर' और 'जनरेटर'

पायथन में दो जनरेटर कैसे जुड़ें?


1
मैं भी इस तरह से काम करना चाहता हूँ। बिल्कुल वही त्रुटि हुई!
एडम कुर्कविक्ज़

जवाबों:


232

मुझे लगता है कि itertools.chain()यह करना चाहिए।


5
एक को ध्यान में रखना चाहिए कि रिटर्न का itertools.chain()रिटर्न एक types.GeneratorTypeउदाहरण नहीं है। बस मामले में सटीक प्रकार महत्वपूर्ण है।
रीगा

1
आप नीचे दिए गए उदाहरण का काम क्यों नहीं करते?
चार्ली पार्कर

74

कोड का एक उदाहरण:

from itertools import chain

def generator1():
    for item in 'abcdef':
        yield item

def generator2():
    for item in '123456':
        yield item

generator3 = chain(generator1(), generator2())
for item in generator3:
    print item

10
इस उदाहरण को पहले से मौजूद, अत्यधिक उत्क्रमित itertools.chain()उत्तर से क्यों नहीं जोड़ा गया ?
जीन-फ्रांकोइस कॉर्बेट

51

पायथन (3.5 या अधिक) में आप कर सकते हैं:

def concat(a, b):
    yield from a
    yield from b

7
इतना पार्थिक।
रमजान पोलाट

9
अधिक सामान्य: def chain(*iterables): for iterable in iterables: yield from iterable(रखो defऔर for। डालें ताकि जब आप इसे चलाते)
wjandrea

क्या बी से किसी भी चीज की पैदावार लेने से पहले सब कुछ एक उपज से लिया जाता है या उन्हें वैकल्पिक किया जा रहा है?
समस्या

@problemofficer Yup केवल aतब तक जाँच की जाती है जब तक कि सब कुछ उससे प्राप्त न हो जाए, भले ही bवह पुनरावृत्ति न हो। TypeErrorके लिए bनहीं किया जा रहा पुनरावर्तक बाद में आ जाते हैं।
जीट्रांसिट

35

सरल उदाहरण:

from itertools import chain
x = iter([1,2,3])      #Create Generator Object (listiterator)
y = iter([3,4,5])      #another one
result = chain(x, y)   #Chained x and y

3
इस उदाहरण को पहले से मौजूद, अत्यधिक उत्क्रमित itertools.chain()उत्तर से क्यों नहीं जोड़ा गया ?
जीन-फ्रांकोइस कॉर्बेट

यह काफी सही नहीं है, क्योंकि itertools.chainएक पुनरावृत्ति रिटर्न, एक जनरेटर नहीं।
डेविड जे।

तुम बस नहीं कर सकते chain([1, 2, 3], [3, 4, 5])?
कॉर्मन

10

Itertools.chain.from_iterable के साथ आप निम्न कार्य कर सकते हैं:

def genny(start):
  for x in range(start, start+3):
    yield x

y = [1, 2]
ab = [o for o in itertools.chain.from_iterable(genny(x) for x in y)]
print(ab)

आप एक अनावश्यक सूची समझ का उपयोग कर रहे हैं। gennyजब आप पहले से ही एक जनरेटर लौटाते हैं तो आप एक अनावश्यक जनरेटर अभिव्यक्ति का उपयोग कर रहे हैं । list(itertools.chain.from_iterable(genny(x)))अधिक संक्षिप्त है।
कॉर्मैन

इस सवाल के अनुसार, ist comprehension दो जनरेटर बनाने का एक आसान तरीका था। हो सकता है कि मेरा उत्तर उस संबंध में थोड़ा आश्वस्त हो।
andrew pate

मुझे लगता है कि जिस कारण से मैंने इस उत्तर को मौजूदा लोगों के साथ जोड़ा था वह उन लोगों की मदद करने के लिए था, जिनके साथ सौदा करने के लिए बहुत सारे जनरेटर होते हैं।
andrew pate

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

Corman, मैं मानता हूं कि आपकी सूची निर्माता वास्तव में अधिक पठनीय है। हालांकि आपके 'कई आसान तरीकों' को देखना अच्छा होगा ... मुझे लगता है कि ऊपर wjandrea की टिप्पणी itertools.chain.from_iterable की तरह ही लग रही है, इसलिए यह अच्छा होगा कि आप उन्हें रेस दें और सबसे तेज़ देखें।
andrew pate

8

यहां यह नेस्टेड एस के साथ एक जनरेटर अभिव्यक्ति का उपयोग कर रहा है for:

a = range(3)
b = range(5)
ab = (i for it in (a, b) for i in it)
assert list(ab) == [0, 1, 2, 0, 1, 2, 3, 4]

2
थोड़ी व्याख्या से दुख नहीं होगा।
रमजान पोलाट

खैर, मुझे नहीं लगता कि मैं इसे पायथन के प्रलेखन से बेहतर समझा सकता हूं।
अलेक्सई

(जनरेटर अभिव्यक्तियों के लिए प्रलेखन मेरे उत्तर से जुड़ा हुआ है। मुझे अपने उत्तर में दस्तावेज को कॉपी और पेस्ट करने का एक अच्छा कारण नहीं दिखता है।)
एलेक्सी

3

एक भी अनपैक ऑपरेटर का उपयोग कर सकता है *:

concat = (*gen1(), *gen2())

नोट: 'गैर-आलसी' पुनरावृत्तियों के लिए सबसे कुशलता से काम करता है। विभिन्न प्रकार की समझ के साथ भी इस्तेमाल किया जा सकता है। जेनरेटर कॉनैट के लिए पसंदीदा तरीका @ यूड्यूस के उत्तर से होगा


1

यदि आप जनरेटर को अलग रखना चाहते हैं, लेकिन फिर भी उन पर पुनरावृति करते हैं, तो आप ज़िप () का उपयोग कर सकते हैं:

नोट: Iteration दो जनरेटर के छोटे पर बंद हो जाता है

उदाहरण के लिए:

for (root1, dir1, files1), (root2, dir2, files2) in zip(os.walk(path1), os.walk(path2)):

    for file in files1:
        #do something with first list of files

    for file in files2:
        #do something with second list of files

0

आइए हम कहते हैं कि हमें जनरेटर (जीन 1 और जीन 2) को प्राप्त करना है और हम कुछ अतिरिक्त गणना करना चाहते हैं जिसके लिए दोनों के परिणाम की आवश्यकता होती है। हम मानचित्र विधि के माध्यम से ऐसे फ़ंक्शन / गणना के परिणाम को वापस कर सकते हैं, जो बदले में एक जनरेटर देता है जिसे हम लूप कर सकते हैं।

इस परिदृश्य में, फ़ंक्शन / गणना को लंबो फ़ंक्शन के माध्यम से कार्यान्वित करने की आवश्यकता होती है। मुश्किल हिस्सा वह है जो हम नक्शे और उसके लंबो फ़ंक्शन के अंदर करना चाहते हैं।

प्रस्तावित समाधान का सामान्य रूप:

def function(gen1,gen2):
        for item in map(lambda x, y: do_somethin(x,y), gen1, gen2):
            yield item

0

उन सभी जटिल समाधान ...

बस करो:

for dir in director_1, directory_2:
    for directory, dirs, files in os.walk(dir):
        do_something()

यदि आप वास्तव में दोनों जनरेटर को "जोड़ना" चाहते हैं, तो करें:

for directory, dirs, files in 
        [x for osw in [os.walk(director_1), os.walk(director_2)] 
               for x in osw]:
    do_something()
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.