2009-10-25 9 views
1

J'aime utiliser l'expression suivante pour combiner des listes ensemble, parfois:expressions du générateur nichant dans la liste des arguments pour un appel de fonction python

>>> 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 à obtenir ce résultat particulier, mais il vient est très pratique lorsque vous voulez itérer sur les éléments dans les listes de listes de listes, ou quelque chose comme ça. Le problème est, lorsque vous utilisez des expressions du générateur, cela devient sujette 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')] 

Qu'est-ce qui se passe voici que le générateur interne expresse les ions sont passés comme arguments à itertools.chain, donc au moment où ils sont évalués, l'expression du générateur externe est terminée, et n est fixée à sa valeur finale, 'b'. Je me demande si quelqu'un a pensé à des façons d'éviter ce genre d'erreur, au-delà de "ne fais pas ça".

Répondre

2

Votre approche fonctionne presque, vous avez juste besoin d'aplatir les générateurs. Voyez comment le for e in l est déplacé vers la droite sur

>>> 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 en utilisant 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é à passer les tuples 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')] 
+0

Merci, la fonction produit semble devoir être plus sûre et conduire à des expressions plus claires. –

6

Est-ce qu'une compréhension de liste imbriquée ne serait 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')] 
+0

Vous pouvez tout coller dans la liste de compréhension, dans ce cas, mais c'est plus compliqué à faire dans certains cas. J'ai simplifié l'exemple pour plus de clarté. –

+2

pourquoi le coller dans une seule ligne? pourquoi ne pas juste imbriqué pour les boucles? cela serait à la fois plus clair et ne nécessitera pas la construction de listes intermédiaires. – SilentGhost

+0

mais n'est pas question de 'expressions de générateur' ne fonctionne pas? –

0

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)) 

Il est beaucoup plus lisible que votre famille de solutions. L'envie n'est pas une bonne chose.