Comprendre la liste sur une liste imbriquée?

219

J'ai cette liste imbriquée:

l = [['40', '20', '10', '30'], ['20', '20', '20', '20', '20', '30', '20'], ['30', '20', '30', '50', '10', '30', '20', '20', '20'], ['100', '100'], ['100', '100', '100', '100', '100'], ['100', '100', '100', '100']]

Maintenant, ce que je veux faire, c'est convertir chaque élément d'une liste en float. Ma solution est la suivante:

newList = []
for x in l:
  for y in x:
    newList.append(float(y))

Mais cela peut-il être fait en utilisant la compréhension de liste imbriquée, non?

ce que j'ai fait c'est:

[float(y) for y in x for x in l]

Mais le résultat est un tas de 100 avec la somme de 2400.

toute solution, une explication serait très appréciée. Merci!

Boy Pasmo
la source
15
Voulez-vous également aplatir votre liste?
Greg Hewgill
@GregHewgill: OP n'a pas répondu, mais d'après la réponse qu'ils ont acceptée, il semble qu'ils voulaient conserver l'imbrication telle quelle.
smci

Réponses:

317

Voici comment procéder avec une compréhension de liste imbriquée:

[[float(y) for y in x] for x in l]

Cela vous donnerait une liste de listes, semblable à celle avec laquelle vous avez commencé, sauf avec des flottants au lieu de chaînes. Si vous voulez une seule liste plate, vous l'utiliserez [float(y) for x in l for y in x].

Andrew Clark
la source
191

Voici comment convertir la compréhension de la boucle imbriquée en liste imbriquée:

entrez la description de l'image ici

Voici comment fonctionne la compréhension des listes imbriquées:

            l a b c d e f
                  
In [1]: l = [ [ [ [ [ [ 1 ] ] ] ] ] ]
In [2]: for a in l:
   ...:     for b in a:
   ...:         for c in b:
   ...:             for d in c:
   ...:                 for e in d:
   ...:                     for f in e:
   ...:                         print(float(f))
   ...:                         
1.0

In [3]: [float(f)
         for a in l
   ...:     for b in a
   ...:         for c in b
   ...:             for d in c
   ...:                 for e in d
   ...:                     for f in e]
Out[3]: [1.0]

Pour votre cas, ce sera quelque chose comme ça.

In [4]: new_list = [float(y) for x in l for y in x]
Rahul
la source
21
Super utile! Indique clairement que les boucles (de haut en bas) sont ordonnées de gauche à droite dans le générateur. Ce n'est pas évident car en (f(x) for x in l)place la deuxième ligne de l'équivalent pour la boucle à gauche.
user48956
Cela semble être la seule explication qui me rentre vraiment à la maison, merci!
Douglas Plumley
48
>>> l = [['40', '20', '10', '30'], ['20', '20', '20', '20', '20', '30', '20'], ['30', '20', '30', '50', '10', '30', '20', '20', '20'], ['100', '100'], ['100', '100', '100', '100', '100'], ['100', '100', '100', '100']]
>>> new_list = [float(x) for xs in l for x in xs]
>>> new_list
[40.0, 20.0, 10.0, 30.0, 20.0, 20.0, 20.0, 20.0, 20.0, 30.0, 20.0, 30.0, 20.0, 30.0, 50.0, 10.0, 30.0, 20.0, 20.0, 20.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0]
falsetru
la source
42

Vous ne savez pas quelle est votre sortie souhaitée, mais si vous utilisez la compréhension de liste, l'ordre suit l'ordre des boucles imbriquées, que vous avez à l'envers. J'ai donc obtenu ce que je pense que vous voulez:

[float(y) for x in l for y in x]

Le principe est le suivant: utilisez le même ordre que vous utiliseriez pour l'écrire comme imbriqué pour les boucles.

Harry Binswanger
la source
cela devrait être la réponse, car parfois nous ne voulons pas mettre l'itératool entre crochets
zinking le
1
ce n'est peut-être pas la bonne réponse car elle génère une liste non imbriquée, mais c'est ce que je cherchais, en particulier le principe . Merci!
Rodrigo E. Principe
4

Comme je suis un peu en retard ici, mais je voulais partager comment fonctionne réellement la compréhension de liste, en particulier la compréhension de liste imbriquée:

New_list= [[float(y) for x in l]

est en fait identique à:

New_list=[]
for x in l:
    New_list.append(x)

Et maintenant compréhension des listes imbriquées:

[[float(y) for y in x] for x in l]

est identique à;

new_list=[]
for x in l:
    sub_list=[]
    for y in x:
        sub_list.append(float(y))

    new_list.append(sub_list)

print(new_list)

production:

[[40.0, 20.0, 10.0, 30.0], [20.0, 20.0, 20.0, 20.0, 20.0, 30.0, 20.0], [30.0, 20.0, 30.0, 50.0, 10.0, 30.0, 20.0, 20.0, 20.0], [100.0, 100.0], [100.0, 100.0, 100.0, 100.0, 100.0], [100.0, 100.0, 100.0, 100.0]]
Aaditya Ura
la source
3

Si vous n'aimez pas les compréhensions de listes imbriquées, vous pouvez également utiliser la fonction de carte ,

>>> from pprint import pprint

>>> l = l = [['40', '20', '10', '30'], ['20', '20', '20', '20', '20', '30', '20'], ['30', '20', '30', '50', '10', '30', '20', '20', '20'], ['100', '100'], ['100', '100', '100', '100', '100'], ['100', '100', '100', '100']] 

>>> pprint(l)
[['40', '20', '10', '30'],
['20', '20', '20', '20', '20', '30', '20'],
['30', '20', '30', '50', '10', '30', '20', '20', '20'],
['100', '100'],
['100', '100', '100', '100', '100'],
['100', '100', '100', '100']]

>>> float_l = [map(float, nested_list) for nested_list in l]

>>> pprint(float_l)
[[40.0, 20.0, 10.0, 30.0],
[20.0, 20.0, 20.0, 20.0, 20.0, 30.0, 20.0],
[30.0, 20.0, 30.0, 50.0, 10.0, 30.0, 20.0, 20.0, 20.0],
[100.0, 100.0],
[100.0, 100.0, 100.0, 100.0, 100.0],
[100.0, 100.0, 100.0, 100.0]]
narayan
la source
Votre code génère des objets cartographiques au lieu de listes: >>> float_l = [map(float, nested_list) for nested_list in l] [[<map at 0x47be9b0>], [<map at 0x47be2e8>], [<map at 0x47be4a8>], [<map at 0x47beeb8>], [<map at 0x484b048>], [<map at 0x484b0b8>]] mais en ajoutant un appel supplémentaire à la liste, cela fonctionne comme prévu: >>> float_l = [list(map(float, nested_list)) for nested_list in l]
pixelperfect
@pixelperfect qui est dû au changement ( mal informé ..) python3pour renvoyer les générateurs hors de compréhension.
javadba
3

J'avais un problème similaire à résoudre, alors je suis tombé sur cette question. J'ai fait une comparaison des performances de la réponse d'Andrew Clark et de narayan que je voudrais partager.

La principale différence entre deux réponses est la façon dont elles parcourent les listes internes. L'un d'eux utilise une carte intégrée , tandis que l'autre utilise la compréhension de liste. La fonction de carte présente un léger avantage en termes de performances par rapport à sa compréhension de liste équivalente si elle ne nécessite pas l'utilisation de lambdas . Donc, dans le contexte de cette question, la mapcompréhension de la liste devrait être légèrement meilleure.

Permet de faire un benchmark de performance pour voir si c'est vraiment vrai. J'ai utilisé python version 3.5.0 pour effectuer tous ces tests. Dans la première série de tests, je voudrais garder les éléments par liste à 10 et faire varier le nombre de listes de 10 à 100 000

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,10))]*10]"
>>> 100000 loops, best of 3: 15.2 usec per loop   
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,10))]*10]"
>>> 10000 loops, best of 3: 19.6 usec per loop 

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,10))]*100]"
>>> 100000 loops, best of 3: 15.2 usec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,10))]*100]"
>>> 10000 loops, best of 3: 19.6 usec per loop 

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,10))]*1000]"
>>> 1000 loops, best of 3: 1.43 msec per loop   
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,10))]*1000]"
>>> 100 loops, best of 3: 1.91 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,10))]*10000]"
>>> 100 loops, best of 3: 13.6 msec per loop   
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,10))]*10000]"
>>> 10 loops, best of 3: 19.1 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,10))]*100000]"
>>> 10 loops, best of 3: 164 msec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,10))]*100000]"
>>> 10 loops, best of 3: 216 msec per loop

entrez la description de l'image ici

Dans la prochaine série de tests, je voudrais augmenter le nombre d'éléments par listes à 100 .

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,100))]*10]"
>>> 10000 loops, best of 3: 110 usec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,100))]*10]"
>>> 10000 loops, best of 3: 151 usec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,100))]*100]"
>>> 1000 loops, best of 3: 1.11 msec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,100))]*100]"
>>> 1000 loops, best of 3: 1.5 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,100))]*1000]"
>>> 100 loops, best of 3: 11.2 msec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,100))]*1000]"
>>> 100 loops, best of 3: 16.7 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,100))]*10000]"
>>> 10 loops, best of 3: 134 msec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,100))]*10000]"
>>> 10 loops, best of 3: 171 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,100))]*100000]"
>>> 10 loops, best of 3: 1.32 sec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,100))]*100000]"
>>> 10 loops, best of 3: 1.7 sec per loop

entrez la description de l'image ici

Permet de faire un pas courageux et de modifier le nombre d'éléments dans les listes à 1000

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,1000))]*10]"
>>> 1000 loops, best of 3: 800 usec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,1000))]*10]"
>>> 1000 loops, best of 3: 1.16 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,1000))]*100]"
>>> 100 loops, best of 3: 8.26 msec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,1000))]*100]"
>>> 100 loops, best of 3: 11.7 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,1000))]*1000]"
>>> 10 loops, best of 3: 83.8 msec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,1000))]*1000]"
>>> 10 loops, best of 3: 118 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,1000))]*10000]"
>>> 10 loops, best of 3: 868 msec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,1000))]*10000]"
>>> 10 loops, best of 3: 1.23 sec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,1000))]*100000]"
>>> 10 loops, best of 3: 9.2 sec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,1000))]*100000]"
>>> 10 loops, best of 3: 12.7 sec per loop

entrez la description de l'image ici

À partir de ces tests, nous pouvons conclure que cela mapa un avantage sur les performances par rapport à la compréhension des listes. Cela s'applique également si vous essayez de caster sur intou str. Pour un petit nombre de listes avec moins d'éléments par liste, la différence est négligeable. Pour des listes plus grandes avec plus d'éléments par liste, on pourrait utiliser mapau lieu de la compréhension de la liste, mais cela dépend totalement des besoins de l'application.

Cependant, je trouve personnellement que la compréhension de la liste est plus lisible et idiomatique que map. C'est un standard de facto en python. Habituellement, les gens sont plus compétents et plus à l'aise (spécialement les débutants) pour utiliser la compréhension de liste que map.

Sohaib Farooqi
la source
2

Oui, vous pouvez le faire avec un tel code:

l = [[float(y) for y in x] for x in l]
Victor
la source
[float(y) for y in x for x in l]cela se traduirait par un tas de 100 avec une somme de 2400.
Boy Pasmo
2

Ce problème peut être résolu sans utiliser de boucle. Un code de ligne unique sera suffisant pour cela. L'utilisation de la carte imbriquée avec la fonction lambda fonctionne également ici.

l = [['40', '20', '10', '30'], ['20', '20', '20', '20', '20', '30', '20'], ['30', '20', '30', '50', '10', '30', '20', '20', '20'], ['100', '100'], ['100', '100', '100', '100', '100'], ['100', '100', '100', '100']]

map(lambda x:map(lambda y:float(y),x),l)

Et la liste de sortie serait la suivante:

[[40.0, 20.0, 10.0, 30.0], [20.0, 20.0, 20.0, 20.0, 20.0, 30.0, 20.0], [30.0, 20.0, 30.0, 50.0, 10.0, 30.0, 20.0, 20.0, 20.0], [100.0, 100.0], [100.0, 100.0, 100.0, 100.0, 100.0], [100.0, 100.0, 100.0, 100.0]]
Aakash Goel
la source
1
Lambdas a-t-il des avantages en termes de performances par rapport aux solutions @Andrew Clark ou Harry Binswanger (la compréhension de la liste la plus vanillée)? Comme les lambdas semblent plus difficiles à lire.
StefanJCollier
0

La meilleure façon de le faire à mon avis est d'utiliser le itertoolspaquet de python .

>>>import itertools
>>>l1 = [1,2,3]
>>>l2 = [10,20,30]
>>>[l*2 for l in itertools.chain(*[l1,l2])]
[2, 4, 6, 20, 40, 60]
Thomasillo
la source
0

Oui, vous pouvez effectuer les opérations suivantes.

[[float(y) for y in x] for x in l]
user1142317
la source
-2
    deck = [] 
    for rank in ranks:
        for suit in suits:
            deck.append(('%s%s')%(rank, suit))

Ceci peut être réalisé en utilisant la compréhension de la liste:

[deck.append((rank,suit)) for suit in suits for rank in ranks ]
ADITYA KUMAR
la source
1
Cela ne semble pas répondre du tout à la question. Veuillez noter que tout ce qui est affiché comme réponse doit être une tentative de répondre à la question à laquelle il est envoyé.
Baum mit Augen
Bien que cet extrait de code puisse résoudre la question, y compris une explication aide vraiment à améliorer la qualité de votre message. N'oubliez pas que vous répondrez à la question pour les lecteurs à l'avenir, et ces personnes pourraient ne pas connaître les raisons de votre suggestion de code. Essayez également de ne pas surcharger votre code avec des commentaires explicatifs, cela réduit la lisibilité du code et des explications!
Filnor
Imbriqué pour la boucle en utilisant la compréhension de liste,
ADITYA KUMAR
1
Ok, donc apparemment, c'est une tentative de répondre à la question. Cependant, cela semble concerner un scénario entièrement différent de celui d'OP, vous ne traitez même pas les listes imbriquées en entrée, et même si vous changez cela, votre suggestion est à peu près ce que OP a déjà essayé. De plus, je ne vois pas comment un exemple sur les cartes aide lorsque la question est de convertir des chaînes en flottant.
Baum mit Augen