2013-01-12 14 views
15

Jeśli mam dwie tablice, tej samej długości - mówią a i bCo to jest pythonic sposób przechodzenia przez dwie tablice w tym samym czasie?

a = [4,6,2,6,7,3,6,7,2,5]

b = [6,4,6,3,2,7,8,5,3,5]

normalnie, zrobiłbym to tak:

for i in range(len(a)): 
    print a[i] + b[i] 

zamiast coś tak:

i=0 
for number in a: 
    print number + b[i] 
    i += 1 

ponieważ preferuję spójność z używanymi metodami.

Znam zip, ale nigdy go nie używam. Czy to właśnie stworzono zip?

byłoby

for pair in zip(a,b): 
    print pair[0] + pair[1] 

być pythonic sposób to zrobić?

Odpowiedz

17

Jeżeli wykazy a i b są krótkie, użyj zip (jak @Vincenzo Pii pokazał):

for x, y in zip(a, b): 
    print(x + y) 

Jeżeli wykazy a i b są długie, a następnie użyć itertools.izip zapisać Pamięć:

import itertools as IT 
for x, y in IT.izip(a, b): 
    print(x + y) 

zip tworzy listę krotek. Może to być uciążliwe (pod względem pamięci), jeśli są one duże.

itertools.izip zwraca iterator. Iterator nie generuje pełnej listy krotek; daje tylko każdą pozycję, jak żąda pętla for. W ten sposób można zaoszczędzić trochę pamięci.

Wywołanie Python2 zip(a,b) na krótkich listach jest szybsze niż użycie itertools.izip(a,b). Ale w Python3 zauważ, że zip zwraca domyślnie iterator (tj. Jest to odpowiednik itertools.izip w Pythonie2).


Inne warianty to:

+1

Aby to zrobić, wspomniałbym również o 'future_builtins'. – georg

+0

Więc w zip w python3 jest taki sam jak itertools.izip? A może zmienia się w zależności od wielkości list? – will

+2

@will: Tak, 'zip' w Python3 jest taki sam jak' itertools.izip' w Python2. (Nie zmienia to zachowania z rozmiarem listy.) Aby uzyskać stare zachowanie 'zip' w Python3, użyj' list (zip (a, b)). – unutbu

7

Możliwym rozwiązaniem jest użycie zip, jak wspomniano siebie, ale w nieco inny sposób niż jak to napisał w pytaniu:

for x, y in zip(a, b): 
    print x, y 

Zauważ, że długość listy krotek zwracane przez zip() będzie równa do minimum między długościami a i b. Ma to wpływ, gdy a i b nie ma tej samej długości.

+0

To wygląda bardzo znajomo z różnych przykładów i stron dokumentacji – will

+0

To potwierdza, że ​​jest pythonic :)! –

4

Zamiast używać zip można użyć Numpy, zwłaszcza jeśli szybkość jest ważna i masz długie tablice. Jest o wiele szybciej i raz używasz numpy tablice nie trzeba pętlę, a może po prostu napisać:

print a + b 

wykres przedstawiający uśrednione czasy dla zsumowanie różnych list długości za pomocą zip, iZIP i numpy: enter image description here

+1

Yah wiem o numpy. Jest to z pewnością zastosowanie w tym przypadku, ale podany przeze mnie przykład był po prostu sztuczny. Naprawdę chcę tego, gdy masz dwie listy obiektów i chcesz uzyskać dostęp do n-tego obiektu obu. Stało się dla mnie jasne, gdy chciałem dodać wzór "kreskowania" do "klina" w kole "matplotlib". Końcowym zastosowaniem będzie coś w stylu 'dla wzoru, klina w suwaku (wzory, kliny): wedge.set_hatch (wzór)' – will

0

Proponowanie tej odpowiedzi pod kątem kompletności od numpy zostało omówione w innej odpowiedzi, a często przydatne jest parowanie wartości z tablic o wyższej pozycji.

accepted answer doskonale do dowolnej sekwencji/tablicy stopnia 1. Jednakże, jeśli sekwencja wielu poziomach (takich jak numpy tablicy 2 stopień lub więcej, ale także, tak jak w list z list S albo tuple z tuple s), należy iterować przez każdą pozycję. Poniżej znajduje się przykład z 2D numpy tablicy:

import numpy as np 
a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) 
b = np.array([list('abc'), list('pdq'), list('xyz')]) 
c = np.array([[frobnicate(aval, bval) for aval, bval in zip(arow, brow)] for arow, brow in zip(a, b)]) 

A sama koncepcja będzie pracować dla dowolnego zbioru dwuwymiarowych zagnieżdżonych sekwencji o tym samym kształcie:

a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] 
b = [list('abc'), list('pdq'), list('xyz')] 
c = [[frobnicate(aval, bval) for aval, bval in zip(arow, brow)] for arow, brow in zip(a, b)] 

Jeśli jeden lub oba z zagnieżdżonych sekwencje ma „dziury” w nim, używają itertools.zip_longest wypełnić otwory (domyślne wartości napełnienia do None ale może być określona):

from itertools import zip_longest as zipl 
a = [[], [4, 5, 6], [7, 8, 9]] # empty list in the first row 
b = [list('abc'), list('pdq'), []] # empty list in the last row 
c = [[frobnicate(aval, bval) for aval, bval in zipl(arow, brow)] for arow, brow in zipl(a, b)] 
Powiązane problemy