Zrozumienie listy na liście zagnieżdżonej?

219

Mam tę zagnieżdżoną listę:

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

Teraz chcę przekonwertować każdy element z listy na pływający. Moje rozwiązanie jest następujące:

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

Ale czy można tego dokonać przy użyciu listy zagnieżdżonej, prawda?

co zrobiłem to:

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

Ale wtedy wynikiem jest wiązka setek z sumą 2400.

każde rozwiązanie, wyjaśnienie byłoby bardzo mile widziane. Dzięki!

Boy Pasmo
źródło
15
Czy chcesz także spłaszczyć swoją listę?
Greg Hewgill,
@GregHewgill: OP nie odpowiedział, ale na podstawie odpowiedzi, którą zaakceptowali, wygląda na to, że chcieli zachować zagnieżdżenie w obecnej formie.
smci

Odpowiedzi:

318

Oto jak to zrobiłbyś ze zrozumieniem zagnieżdżonej listy:

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

To da ci listę list, podobną do tej, którą zacząłeś, z wyjątkiem pływaków zamiast ciągów. Jeśli chcesz mieć jedną płaską listę, skorzystaj [float(y) for x in l for y in x].

Andrew Clark
źródło
191

Oto jak przekonwertować zagnieżdżoną pętlę na zrozumienie listy zagnieżdżonej:

wprowadź opis zdjęcia tutaj

Oto jak działa obsługa list zagnieżdżonych:

            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]

W twoim przypadku będzie to coś takiego.

In [4]: new_list = [float(y) for x in l for y in x]
Rahul
źródło
21
Super przydatne! Wyjaśnia, że ​​pętle (od góry do dołu) są uporządkowane od lewej do prawej w generatorze. Nie jest to oczywiste, ponieważ (f(x) for x in l)miejscami druga linia ekwiwalentu pętli for po lewej stronie.
user48956
To chyba jedyne wytłumaczenie, które tak naprawdę trafia ze mną do domu, dziękuję!
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
źródło
42

Nie jestem pewien, jakie są pożądane dane wyjściowe, ale jeśli korzystasz ze zrozumienia listy, kolejność jest zgodna z kolejnością zagnieżdżonych pętli, które masz odwrotnie. Mam więc to, co myślę, że chcesz:

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

Zasada jest taka: używaj tej samej kolejności, w jakiej zapisujesz ją, zagnieżdżonej dla pętli.

Harry Binswanger
źródło
taka powinna być odpowiedź, ponieważ czasami nie chcemy kwadratowego nawiasu kwadratowego iteratool
zinking
1
to może nie być poprawna odpowiedź, ponieważ wyświetla listę nie zagnieżdżoną, ale właśnie tego szukałem, szczególnie zasady . Dzięki!
Rodrigo E. Principe
4

Ponieważ trochę się tutaj spóźniłem, ale chciałem się podzielić tym, jak faktycznie działa interpretacja listy, a zwłaszcza zagnieżdżanie listy:

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

jest w rzeczywistości taki sam jak:

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

A teraz zrozumienie listy zagnieżdżonej:

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

jest taki sam jak;

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)

wynik:

[[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
źródło
3

Jeśli nie podoba Ci się lista zagnieżdżona, możesz również skorzystać z funkcji mapy ,

>>> 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
źródło
Twój kod generuje obiekty map zamiast list: >>> 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>]] ale dodanie dodatkowego wywołania do listy działa zgodnie z oczekiwaniami: >>> float_l = [list(map(float, nested_list)) for nested_list in l]
pixelperfect 17.03.17
@pixelperfect, który jest spowodowany ( źle poinformowaną ..) zmianą, python3aby zwrócić generatory z niezrozumienia.
javadba
3

Miałem podobny problem do rozwiązania, więc natknąłem się na to pytanie. Zrobiłem porównanie wydajności odpowiedzi Andrew Clarka i Narayana, którym chciałbym się podzielić.

Podstawowa różnica między dwiema odpowiedziami polega na tym, jak iterują się po wewnętrznych listach. Jeden z nich korzysta z wbudowanej mapy , podczas gdy inny używa listy. Funkcja mapy ma niewielką przewagę wydajności w porównaniu z równoważnym listowaniem, jeśli nie wymaga użycia lambda . Dlatego w kontekście tego pytania mappowinno działać nieco lepiej niż zrozumienie listy.

Zróbmy test porównawczy wydajności, aby sprawdzić, czy to rzeczywiście prawda. Użyłem Pythona w wersji 3.5.0 do wykonania wszystkich tych testów. W pierwszym zestawie testów chciałbym, aby liczba elementów na liście wynosiła 10, a liczba list od 10 do 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

wprowadź opis zdjęcia tutaj

W następnym zestawie testów chciałbym podnieść liczbę elementów na listy do 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

wprowadź opis zdjęcia tutaj

Zróbmy odważny krok i zmień liczbę elementów na listach na 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

wprowadź opis zdjęcia tutaj

Na podstawie tych testów możemy stwierdzić, że mapw tym przypadku ma on przewagę wydajności nad zrozumieniem listy. Ma to również zastosowanie, jeśli próbujesz przesyłać do jednego intlub jednego str. W przypadku małej liczby list z mniejszą liczbą elementów na listę różnica jest znikoma. W przypadku większych list z większą liczbą elementów na listę można chcieć użyć mapzamiast ich interpretacji, ale zależy to całkowicie od potrzeb aplikacji.

Jednak osobiście uważam, że zrozumienie listy jest bardziej czytelne i idiomatyczne niż map. Jest to de facto standard w Pythonie. Zwykle ludzie są bardziej biegli i wygodni (szczególnie początkujący) w posługiwaniu się listą niż map.

Sohaib Farooqi
źródło
2

Tak, możesz to zrobić za pomocą takiego kodu:

l = [[float(y) for y in x] for x in l]
Zwycięzca
źródło
[float(y) for y in x for x in l]to dałoby kilka setek z sumą 2400.
Boy Pasmo
2

Ten problem można rozwiązać bez użycia pętli, wystarczy do tego pojedynczy kod linii. Działa tu także mapa zagnieżdżona z funkcją lambda.

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)

Lista wyjściowa wyglądałaby następująco:

[[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
źródło
1
Czy lambdas ma jakieś zalety w zakresie wydajności w porównaniu z rozwiązaniami @Andrew Clark lub Harry'ego Binswangera (bardziej zrozumienie listy waniliowej)? Ponieważ lambdy wydają się trudniejsze do odczytania.
StefanJCollier
0

Moim zdaniem najlepszym sposobem na to jest skorzystanie z itertoolspakietu Pythona .

>>>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
źródło
0

Tak, możesz wykonać następujące czynności.

[[float(y) for y in x] for x in l]
użytkownik1142317
źródło
-2
    deck = [] 
    for rank in ranks:
        for suit in suits:
            deck.append(('%s%s')%(rank, suit))

Można to osiągnąć przy użyciu listy:

[deck.append((rank,suit)) for suit in suits for rank in ranks ]
ADITYA KUMAR
źródło
1
Wydaje się, że w ogóle nie dotyczy to pytania. Pamiętaj, że wszystko opublikowane jako odpowiedź musi być próbą odpowiedzi na pytanie, na które zostało wysłane.
Baum mit Augen
Ten fragment kodu może rozwiązać pytanie, ale wyjaśnienie naprawdę pomaga poprawić jakość posta. Pamiętaj, że w przyszłości odpowiadasz na pytanie dla czytelników, a ci ludzie mogą nie znać przyczyn Twojej sugestii kodu. Staraj się również nie tłoczyć kodu objaśniającymi komentarzami, co zmniejsza czytelność zarówno kodu, jak i objaśnień!
Filnor
Zagnieżdżony w pętli przy użyciu list,
ADITYA KUMAR
1
Ok, więc najwyraźniej jest to próba odpowiedzi na pytanie. Wydaje się jednak, że dotyczy to zupełnie innego scenariusza niż w PO, nawet nie radzisz sobie z listami zagnieżdżonymi jako danymi wejściowymi, a nawet jeśli zmienisz, że twoja sugestia jest prawie tym, co OP już próbował. Nie rozumiem też, jak pomaga przykład z kartami, gdy chodzi o konwersję ciągów na zmiennoprzecinkowe.
Baum mit Augen