compréhension de la liste python pour produire deux valeurs en une seule itération

Je veux générer une liste en python comme suit -

[1, 1, 2, 4, 3, 9, 4, 16, 5, 25 .....]

Vous auriez compris, ce n'est rien d'autre que n, n*n

J'ai essayé d'écrire une telle compréhension de liste en python comme suit -

lst_gen = [i, i*i for i in range(1, 10)]

Mais en faisant cela, donne une erreur de syntaxe.

Quel serait un bon moyen de générer la liste ci-dessus via la compréhension de la liste?

32
demandé sur LarsH 2013-05-16 22:33:41

12 réponses

Utiliser itertools.chain.from_iterable:

>>> from itertools import chain
>>> list(chain.from_iterable((i, i**2) for i in xrange(1, 6)))
[1, 1, 2, 4, 3, 9, 4, 16, 5, 25]

Ou vous pouvez également utiliser une fonction generator :

>>> def solve(n):
...     for i in xrange(1,n+1):
...         yield i
...         yield i**2

>>> list(solve(5))
[1, 1, 2, 4, 3, 9, 4, 16, 5, 25]
35
répondu Ashwini Chaudhary 2015-08-09 15:03:53

La question est ancienne, mais juste pour le lecteur curieux, je propose une autre possibilité: Comme indiqué sur le premier post, vous pouvez facilement faire un couple (i, i**2) à partir d'une liste de nombres. Alors vous voulez aplatir ce couple. Il suffit donc d'ajouter l'opération aplatir dans votre compréhension.

[x for i in range(1, 10) for x in (i,i**2)]
7
répondu Yann 2016-10-26 14:50:28
lst_gen = sum([(i, i*i) for i in range(1, 10)],())

Oh, je devrais mentionner la somme casse probablement la règle d'une itération: (

5
répondu Joran Beasley 2013-05-16 18:36:00

Les compréhensions de liste génèrent un élément à la fois. Vos options sont plutôt de changer votre boucle pour ne générer qu'une seule valeur à la fois:

[(i//2)**2 if i % 2 else i//2 for i in range(2, 20)]

Ou pour produire des tuples puis aplatir la liste en utilisant itertools.chain.from_iterable():

from itertools import chain

list(chain.from_iterable((i, i*i) for i in range(1, 10)))

Sortie:

>>> [(i//2)**2 if i % 2 else i//2 for i in range(2, 20)]
[1, 1, 2, 4, 3, 9, 4, 16, 5, 25, 6, 36, 7, 49, 8, 64, 9, 81]
>>> list(chain.from_iterable((i, i*i) for i in range(1, 10)))
[1, 1, 2, 4, 3, 9, 4, 16, 5, 25, 6, 36, 7, 49, 8, 64, 9, 81]
5
répondu Martijn Pieters 2013-05-16 18:38:04

Une astuce peu connue: les compréhensions de liste peuvent avoir plusieurs clauses for.

Par exemple:

>>> [10*x+y for x in range(4) for y in range(3)]
[0, 1, 2, 10, 11, 12, 20, 21, 22, 30, 31, 32]

Dans votre cas particulier, vous pouvez faire:

>>> [x*x if y else x for x in range(5) for y in range(2)]
[0, 0, 1, 1, 2, 4, 3, 9, 4, 16]
4
répondu Jonathan Mayer 2017-04-07 19:01:29

Vous pouvez créer une liste de listes puis utiliser reduce pour les rejoindre.

print [[n,n*n] for n in range (10)]

[[0, 0], [1, 1], [2, 4], [3, 9], [4, 16], [5, 25], [6, 36], [7, 49], [8, 64], [9, 81]]

print reduce(lambda x1,x2:x1+x2,[[n,n*n] for n in range (10)])

[0, 0, 1, 1, 2, 4, 3, 9, 4, 16, 5, 25, 6, 36, 7, 49, 8, 64, 9, 81]

 print reduce(lambda x1,x2:x1+x2,[[n**e for e in range(1,4)]\
 for n in range (1,10)])

[1, 1, 1, 2, 4, 8, 3, 9, 27, 4, 16, 64, 5, 25, 125, 6, 36, 216, 7, 49, 343, 8, 64, 512, 9, 81, 729]

Reduce prend une expression appelable qui prend deux arguments et traite une séquence en commençant par le premier deux éléments. Le résultat de la dernière expression est ensuite utilisé comme premier élément dans les appels suivants. Dans ce cas, chaque liste est ajoutée l'une après l'autre à la première liste de la liste des listes, puis cette liste est renvoyée en conséquence.

Les compréhensions de liste appellent implicitement map avec une expression lambda en utilisant la variable et la séquence définies par l'expression "for var in sequence". Ce qui suit est le même genre de chose.

map(lambda n:[n,n*n],range(1,10))

[[1, 1], [2, 4], [3, 9], [4, 16], [5, 25], [6, 36], [7, 49], [8, 64], [9, 81]]

Je ne suis pas au courant d'une expression Python plus naturelle pour reduce.

3
répondu John Hall 2013-05-16 19:35:45

Une autre option:

reduce(lambda x,y: x + [y, y*y], range(1,10), [])
1
répondu Matthew Plourde 2013-05-16 18:38:41

Une autre option, peut sembler perverse à certains

>>> from itertools import izip, tee
>>> g = xrange(1, 11)
>>> x, y = tee(g)
>>> y = (i**2 for i in y)
>>> z = izip(x, y)
>>> output = []
>>> for k in z:
...     output.extend(k)
... 
>>> print output
[1, 1, 2, 4, 3, 9, 4, 16, 5, 25, 6, 36, 7, 49, 8, 64, 9, 81, 10, 100]
1
répondu iruvar 2013-05-16 19:10:33
>>> lst_gen = [[i, i*i] for i in range(1, 10)]
>>> 
>>> lst_gen
[[1, 1], [2, 4], [3, 9], [4, 16], [5, 25], [6, 36], [7, 49], [8, 64], [9, 81]]
>>> 
>>> [num for elem in lst_gen for num in elem]
[1, 1, 2, 4, 3, 9, 4, 16, 5, 25, 6, 36, 7, 49, 8, 64, 9, 81]

Voici ma référence http://docs.python.org/2/tutorial/datastructures.html

0
répondu Supriya K 2013-05-17 14:34:50

Essayez ce deux liner

lst = [[i, i*i] for i in range(10)]
[lst.extend(i) for i in lst]

Modifier les mathématiques si nécessaire.

ENCORE MIEUX

#Change my_range to be the number you want range() function of
start = 1
my_range = 10
lst = [i/2 if i % 2 == 0 else ((i-1)/2)**2 for i in range(start *2, my_range*2 - 1)]
0
répondu ytpillai 2015-08-07 10:17:46

Tel Que mentionné, itertools est le chemin à parcourir. Voici comment je le ferais, je le trouve plus clair:

[i if turn else i*i for i,turn in itertools.product(range(1,10), [True, False])]
0
répondu ntg 2016-02-10 10:05:56

Beaucoup de trucs dans ce fil. Voici un autre utilisant un générateur à une doublure sans importations

x = (lamdba : [[(yield i), (yield i**2)] for i in range(10)])()

Modifier: Cela déclenchera DeprecatedWarning dans Python 3.7 et SyntaxError dans Python 3.8: https://docs.python.org/dev/whatsnew/3.7.html#deprecated

0
répondu Hielke Walinga 2018-03-17 13:11:05