Pojedyncza linia zagnieżdżona dla pętli

104

Napisałem tę funkcję w Pythonie, która transponuje macierz:

def transpose(m):
    height = len(m)
    width = len(m[0])
    return [ [ m[i][j] for i in range(0, height) ] for j in range(0, width) ]

W trakcie tego procesu zdałem sobie sprawę, że nie do końca rozumiem, jak wykonywana jest pojedyncza linia zagnieżdżona dla pętli. Pomóż mi to zrozumieć, odpowiadając na następujące pytania:

  1. Jaka jest kolejność wykonywania pętli for?
  2. Gdybym miał potrójną zagnieżdżoną pętlę for, jaką kolejność by wykonała?
  3. Jaka byłaby równa nieprzeniknionej pętli for?

Dany,

[ function(i,j) for i,j in object ]
  1. Jakiego typu musi być obiekt, aby użyć go do struktury pętli?
  2. Jaka jest kolejność, w jakiej i i j są przypisywane do elementów w obiekcie?
  3. Czy można to zasymulować inną strukturą pętli for?
  4. Czy pętla for może być zagnieżdżona z podobną lub inną strukturą pętli? A jak by to wyglądało?

Dodatkowe informacje są również mile widziane.

Asher Garland
źródło

Odpowiedzi:

171

Najlepszym źródłem informacji jest oficjalny samouczek Pythona dotyczący rozumienia list . Listy składane są prawie takie same jak pętle for (z pewnością każde rozumienie list można zapisać jako pętlę for), ale często są one szybsze niż użycie pętli for.

Spójrz na to dłuższe rozumienie listy z samouczka ( ifczęść filtruje rozumienie, tylko części, które przechodzą instrukcję if, są przekazywane do końcowej części rozumienia listy (tutaj (x,y)):

>>> [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

Działa dokładnie tak samo, jak ta zagnieżdżona pętla for (i, jak mówi samouczek, zwróć uwagę, jak kolejność for i if są takie same).

>>> combs = []
>>> for x in [1,2,3]:
...     for y in [3,1,4]:
...         if x != y:
...             combs.append((x, y))
...
>>> combs
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

Główną różnicą między rozumieniem listy a pętlą for jest to, że ostatnia część pętli for (w której coś robisz) pojawia się na początku, a nie na końcu.

Przejdźmy do pytań:

Jakiego typu musi być obiekt, aby użyć go do struktury pętli?

Iterable . Dowolny obiekt, który może wygenerować (skończony) zbiór elementów. Należą do nich wszelkie kontenery, listy, zestawy, generatory itp.

Jaka jest kolejność, w jakiej i i j są przypisywane do elementów w obiekcie?

Są przypisywane dokładnie w tej samej kolejności, w jakiej są generowane z każdej listy, tak jakby były w zagnieżdżonej pętli for (dla pierwszego zrozumienia dostaniesz 1 element dla i, a następnie każdą wartość z j, drugi element do i, następnie każda wartość z j itp.)

Czy można to zasymulować inną strukturą pętli for?

Tak, już pokazane powyżej.

Czy pętla for może być zagnieżdżona z podobną lub inną strukturą pętli? A jak by to wyglądało?

Jasne, ale to nie jest dobry pomysł. Tutaj, na przykład, daje listę list znaków:

[[ch for ch in word] for word in ("apple", "banana", "pear", "the", "hello")]
Jeff Tratner
źródło
Ciekawe, co kierowało ich wyborem kolejności w zagnieżdżeniu podwójnym. Drugi sposób wydaje mi się bardziej naturalny (w twoim przykładzie dla y, a potem dla x). Po prostu zdaję sobie sprawę, że po 3 latach robienia w Pythonie (nie szeroko, ale nadal ...) i używania tego typu pętli !!
Thomas
@Thomas Drugi sposób też uważam za bardziej intuicyjny. Uważam, że wybór był czystą wygodą. Robienie tego w bardziej intuicyjny sposób oznaczałoby konieczność radzenia sobie z nierozwiązanymi symbolami, dopóki nie znajdzie ich w dalszej części instrukcji. Spróbuj przeanalizować dla każdego banana.peel w każdym bananie dla każdego miasta.bananastore w każdym mieście na papierze. Nie takie proste. Ale na odwrót, miło i łatwo.
Pyjong
30

Może Cię zainteresować itertools.productfunkcja, która zwraca iterowalne, dając krotki wartości ze wszystkich iterowalnych, które ją przekazujesz. Oznacza to, że itertools.product(A, B)zwraca wszystkie wartości formularza (a, b), skąd apochodzą wartości Ai bskąd pochodzą B. Na przykład:

import itertools

A = [50, 60, 70]
B = [0.1, 0.2, 0.3, 0.4]

print [a + b for a, b in itertools.product(A, B)]

To drukuje:

[50.1, 50.2, 50.3, 50.4, 60.1, 60.2, 60.3, 60.4, 70.1, 70.2, 70.3, 70.4]

Zauważ, że ostatni przekazany argument itertools.productjest argumentem „wewnętrznym”. Ogólnie jest równyitertools.product(a0, a1, ... an)[(i0, i1, ... in) for in in an for in-1 in an-1 ... for i0 in a0]

Lynn
źródło
4

Po pierwsze, twój pierwszy kod nie używa pętli for per se, ale rozumienia listy .

  1. Byłoby równoważne

    dla j w zakresie (0, szerokość): dla i w zakresie (0, wysokość): m [i] [j]

  2. Podobnie jak w przypadku pętli, od prawej do lewej. Ale składnia list złożonych jest bardziej złożona.

  3. Nie jestem pewien, o co chodzi w tym pytaniu


  1. Dowolny iterowalny obiekt, który daje iterowalne obiekty, które dają dokładnie dwa obiekty (co za kęs - tj. [(1,2),'ab']Byłby prawidłowy)

  2. Kolejność, w jakiej obiekt podlega iteracji. iidzie do pierwszego plonu, jdrugiego.

  3. Tak, ale nie tak ładnie. Uważam, że jest funkcjonalnym odpowiednikiem:

    l = lista ()
    dla i, j w obiekcie:
        l.append (funkcja (i, j))
    

    lub jeszcze lepiej użyj mapy :

    map(function, object)

    Ale oczywiście funkcja musiałaby dostać i, jsam.

  4. Czy to nie jest to samo pytanie co 3?

Korylprince
źródło
2

Możesz użyć dwóch pętli for w tej samej linii, używając zipfunkcji

Kod:

list1 = ['Abbas', 'Ali', 'Usman']
list2 = ['Kamran', 'Asgar', 'Hamza', 'Umer']
list3 = []
for i,j in zip(list1,list2):
    list3.append(i)
    list3.append(j)
print(list3)

Wynik:

['Abbas', 'Kamran', 'Ali', 'Asgar', 'Usman', 'Hamza']

Tak więc, używając funkcji zip, możemy użyć dwóch pętli for lub możemy iterować dwie listy w tym samym wierszu.

Muhammad Abbas
źródło
-1

Poniższy kod zawiera najlepsze przykłady zagnieżdżonych pętli. Podczas używania dwóch pętli for należy pamiętać, że wyjście pierwszej pętli jest wejściem dla drugiej pętli. Zakończenie pętli jest również ważne podczas korzystania z zagnieżdżonych pętli

for x in range(1, 10, 1):
     for y in range(1,x):
             print y,
        print
OutPut :
1
1 2
1 2 3
1 2 3 4
1 2 3 4 5
1 2 3 4 5 6
1 2 3 4 5 6 7
1 2 3 4 5 6 7 8
rameshbabu reddy
źródło