Listenverständnis auf einer verschachtelten Liste?


219

Ich habe diese verschachtelte Liste:

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']]

Jetzt möchte ich jedes Element in einer Liste in float konvertieren. Meine Lösung lautet:

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

Aber kann dies mit dem Verständnis verschachtelter Listen geschehen, oder?

Was ich getan habe ist:

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

Aber dann ist das Ergebnis ein Haufen von 100 mit der Summe von 2400.

Jede Lösung, eine Erklärung wäre sehr dankbar. Vielen Dank!


15
Möchten Sie auch Ihre Liste reduzieren?
Greg Hewgill

@ GregHewgill: OP hat nicht geantwortet, aber basierend auf der Antwort, die sie akzeptiert haben, scheint es, dass sie die Verschachtelung so lassen wollten, wie sie ist.
smci

Antworten:


317

So würden Sie dies mit einem verschachtelten Listenverständnis tun:

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

Dies würde Ihnen eine Liste von Listen geben, ähnlich wie Sie mit Ausnahme von Floats anstelle von Strings begonnen haben. Wenn Sie eine flache Liste möchten, würden Sie verwenden [float(y) for x in l for y in x].


190

So konvertieren Sie verschachtelte for-Schleifen in verschachtelte Listen:

Geben Sie hier die Bildbeschreibung ein

So funktioniert das Verständnis verschachtelter Listen:

            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]

Für Ihren Fall wird es so etwas sein.

In [4]: new_list = [float(y) for x in l for y in x]

21
Super nützlich! Verdeutlicht, dass die Schleifen (von oben nach unten) im Generator von links nach rechts angeordnet sind. Dies ist nicht offensichtlich, da (f(x) for x in l)stellenweise die zweite Zeile des for-loop-Äquivalents links steht.
user48956

Dies scheint die einzige Erklärung zu sein, die mich wirklich beeindruckt, danke!
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]

42

Sie sind sich nicht sicher, welche Ausgabe Sie wünschen, aber wenn Sie das Listenverständnis verwenden, folgt die Reihenfolge der Reihenfolge der verschachtelten Schleifen, die Sie rückwärts haben. Also habe ich das bekommen, von dem ich denke, dass du es willst:

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

Das Prinzip lautet: Verwenden Sie dieselbe Reihenfolge, in der Sie sie als verschachtelt für Schleifen ausschreiben würden.


Dies sollte die Antwort sein, da wir manchmal das Iteratool nicht in eckige Klammern setzen wollen
Zinking

1
Dies ist möglicherweise nicht die richtige Antwort, da eine nicht verschachtelte Liste ausgegeben wird, aber es ist das, wonach ich gesucht habe, insbesondere das Prinzip . Vielen Dank!
Rodrigo E. Principe

4

Da ich hier etwas spät dran bin, wollte ich aber mitteilen, wie das Listenverständnis tatsächlich funktioniert, insbesondere das verschachtelte Listenverständnis:

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

ist eigentlich das gleiche wie:

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

Und jetzt verschachteltes Listenverständnis:

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

ist das gleiche wie;

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)

Ausgabe:

[[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]]

3

Wenn Sie das Verständnis verschachtelter Listen nicht mögen, können Sie auch die Kartenfunktion verwenden.

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

Ihr Code generiert Kartenobjekte anstelle von Listen. >>> 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>]] >>> float_l = [list(map(float, nested_list)) for nested_list in l]
Wenn

@pixelperfect, das auf die ( falsch informierte ..) Änderung zurückzuführen ist python3, um Generatoren aus dem Verständnis zurückzugeben.
Javadba

3

Ich hatte ein ähnliches Problem zu lösen und bin auf diese Frage gestoßen. Ich habe einen Leistungsvergleich der Antwort von Andrew Clark und Narayan durchgeführt, den ich gerne teilen möchte.

Der Hauptunterschied zwischen zwei Antworten besteht darin, wie sie über innere Listen iterieren. Einer von ihnen verwendet eine integrierte Karte , während der andere das Listenverständnis verwendet. Die Kartenfunktion hat einen leichten Leistungsvorteil gegenüber dem entsprechenden Listenverständnis, wenn keine Lambdas verwendet werden müssen . Im Zusammenhang mit dieser Frage mapsollte also etwas besser abschneiden als das Listenverständnis.

Machen wir einen Leistungsbenchmark, um zu sehen, ob er tatsächlich wahr ist. Ich habe Python Version 3.5.0 verwendet, um all diese Tests durchzuführen. In der ersten Testreihe möchte ich die Anzahl der Elemente pro Liste auf 10 halten und die Anzahl der Listen von 10 bis 100.000 variieren

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

Geben Sie hier die Bildbeschreibung ein

In den nächsten Tests möchte ich die Anzahl der Elemente pro Liste auf 100 erhöhen .

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

Geben Sie hier die Bildbeschreibung ein

Machen wir einen mutigen Schritt und ändern Sie die Anzahl der Elemente in Listen auf 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

Geben Sie hier die Bildbeschreibung ein

Aus diesem Test können wir schließen, dass mapin diesem Fall ein Leistungsvorteil gegenüber dem Listenverständnis besteht. Dies gilt auch, wenn Sie versuchen, entweder intoder zu übertragen str. Bei einer kleinen Anzahl von Listen mit weniger Elementen pro Liste ist der Unterschied vernachlässigbar. Für größere Listen mit mehr Elementen pro Liste möchte man möglicherweise mapanstelle des Listenverständnisses verwenden, dies hängt jedoch vollständig von den Anwendungsanforderungen ab.

Ich persönlich finde das Listenverständnis jedoch lesbarer und idiomatischer als map. Es ist ein De-facto-Standard in Python. Normalerweise beherrschen die Leute das Listenverständnis besser und besser (besonders Anfänger) als map.


2

Ja, Sie können es mit einem solchen Code tun:

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

[float(y) for y in x for x in l]Dies würde zu einem Haufen von 100 mit einer Summe von 2400 führen.
Boy Pasmo

2

Dieses Problem kann ohne Verwendung der for-Schleife gelöst werden. Hierfür ist ein einziger Zeilencode ausreichend. Die Verwendung der verschachtelten Karte mit der Lambda-Funktion funktioniert auch hier.

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)

Die Ausgabeliste wäre wie folgt:

[[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]]

1
Haben Lambdas Leistungsvorteile gegenüber den Lösungen von @Andrew Clark oder Harry Binswanger (je mehr Verständnis für die Vanille-Liste)? Da scheinen Lambdas schwerer zu lesen zu sein.
StefanJCollier

0

Der beste Weg, dies zu tun, ist meiner Meinung nach die Verwendung des Python- itertoolsPakets.

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


-2
    deck = [] 
    for rank in ranks:
        for suit in suits:
            deck.append(('%s%s')%(rank, suit))

Dies kann durch Listenverständnis erreicht werden:

[deck.append((rank,suit)) for suit in suits for rank in ranks ]

1
Dies scheint die obige Frage überhaupt nicht zu beantworten. Bitte beachten Sie, dass alles, was als Antwort gepostet wird, ein Versuch sein muss, die Frage zu beantworten, auf die es gepostet wird.
Baum mit Augen

Während dieses Code-Snippet die Frage lösen kann, hilft das Hinzufügen einer Erklärung wirklich, die Qualität Ihres Beitrags zu verbessern. Denken Sie daran, dass Sie die Frage für Leser in Zukunft beantworten und diese Personen möglicherweise die Gründe für Ihren Codevorschlag nicht kennen. Bitte versuchen Sie auch, Ihren Code nicht mit erklärenden Kommentaren zu überfüllen. Dies verringert die Lesbarkeit sowohl des Codes als auch der Erklärungen!
Filnor

Verschachtelt für Schleife mit Listenverständnis,
ADITYA KUMAR

1
Ok, anscheinend ist dies ein Versuch, die Frage zu beantworten. Dies scheint jedoch ein völlig anderes Szenario zu sein als in OP. Sie behandeln verschachtelte Listen nicht einmal als Eingabe, und selbst wenn Sie ändern, dass Ihr Vorschlag so ziemlich das ist, was OP bereits versucht hat. Ich sehe auch nicht, wie ein Beispiel für Karten hilft, wenn es darum geht, Zeichenfolgen in Float umzuwandeln.
Baum mit Augen
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.