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?
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]
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)]
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: (
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]
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]
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.
Une autre option:
reduce(lambda x,y: x + [y, y*y], range(1,10), [])
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]
>>> 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
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)]
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