web-dev-qa-db-fra.com

Comment joindre deux générateurs en Python?

Je veux changer le code suivant

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

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

à ce code:

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

Je reçois l'erreur:

type (s) d'opérande non pris en charge pour +: 'générateur' et 'générateur'

Comment joindre deux générateurs en Python?

133
Homer Xing

Je pense que itertools.chain() devrait le faire.

180
Philipp

Un exemple de code:

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
44
Cesio

Exemple simple:

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
15
user1767754

En Python (3.5 ou supérieur), vous pouvez faire:

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

Avec itertools.chain.from_iterable, vous pouvez faire des choses comme:

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)
8
andrew pate

Ici, il utilise une expression generator avec des fors imbriqués:

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]
3
Alexey

Disons que nous devons utiliser des générateurs (gen1 et gén2) et que nous souhaitons effectuer des calculs supplémentaires qui nécessitent le résultat des deux ..__ Nous pouvons renvoyer le résultat de cette fonction/calcul par la méthode de la carte, qui renvoie à son tour un générateur sur lequel on peut faire une boucle. 

Dans ce scénario, la fonction/le calcul doit être implémenté via la fonction lambda . La partie délicate est ce que nous visons à faire à l’intérieur de la carte et de sa fonction lambda.

Forme générale de la solution proposée:

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

Si vous voulez garder les générateurs séparés tout en les parcourant en même temps, vous pouvez utiliser Zip ():

NOTE: l'itération s'arrête au plus court des deux générateurs

Par exemple:

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
1
DivideByZero

Toutes ces solutions compliquées ...

il suffit de faire:

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

Si vous voulez vraiment "rejoindre" les deux générateurs, alors faites: 

for directory, dirs, files in 
        [x for osw in [os.walk(director_1), os.walk(director_2)] 
               for x in osw]:
    do_something()
0
Camion