Imbrication des expressions du générateur dans la liste des arguments pour un appel de fonction python

StackOverflow https://stackoverflow.com/questions/1620957

Question

J'aime utiliser l'idiome suivant pour combiner des listes, parfois:

>>> list(itertools.chain(*[[(e, n) for e in l] for n, l in (('a', [1,2]),('b',[3,4]))]))
[(1, 'a'), (2, 'a'), (3, 'b'), (4, 'b')]

(Je sais qu'il existe des moyens plus faciles d'obtenir ce résultat particulier, mais il est très utile lorsque vous souhaitez parcourir les éléments dans les listes de listes de listes, ou quelque chose du genre. Le problème, c'est que vous utilisez générateur. expressions, cela devient sujet aux erreurs, par exemple,

>>> list(itertools.chain(*(((e, n) for e in l) for n, l in (('a', [1,2]),('b',[3,4])))))
[(1, 'b'), (2, 'b'), (3, 'b'), (4, 'b')]

Ce qui se passe ici, c'est que les expressions du générateur interne sont passées en tant qu'arguments à itertools.chain . Ainsi, au moment de leur évaluation, l'expression du générateur externe est terminée et n est fixé à sa valeur finale, 'b' . Je me demande si quelqu'un a pensé à des moyens d'éviter ce genre d'erreur, au-delà de "ne faites pas cela".

Était-ce utile?

La solution

Votre approche fonctionne presque, il vous suffit d’aplatir les générateurs. Voyez comment le for e in l est déplacé à l'extrême droite

>>> list(itertools.chain((e, n) for n, l in (('a', [1,2]),('b',[3,4])) for e in l ))
[(1, 'a'), (2, 'a'), (3, 'b'), (4, 'b')]

Voici comment faire la même chose avec itertools.product

>>> X=itertools.chain(*(itertools.product(*i[::-1]) for i in (('a', [1,2]),('b',[3,4]))))
>>> print list(X)
[(1, 'a'), (2, 'a'), (3, 'b'), (4, 'b')]

ou si vous êtes autorisé à permuter les n-uplets autour

>>> X=itertools.chain(*(itertools.product(*i) for i in (([1,2],'a'),([3,4],'b'))))
>>> print list(X)
[(1, 'a'), (2, 'a'), (3, 'b'), (4, 'b')]

Autres conseils

Une compréhension de liste imbriquée ne serait-elle pas plus appropriée?

>>> tt = (('a', [1,2]),('b',[3,4]))
>>> [(s, i) for i, l in tt for s in l]
[(1, 'a'), (2, 'a'), (3, 'b'), (4, 'b')]

Je vais suggérer

data = (('a', [1,2]), ('b', [3,4]))

result = []
for letter, numbers in data:
     for number in numbers:
         result.append((number, letter))

C’est beaucoup plus lisible que votre famille de solutions. La fantaisie n’est pas une bonne chose.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top