from itertools import izip
def pairwise(iterable):"s -> (s0, s1), (s2, s3), (s4, s5), ..."
a = iter(iterable)return izip(a, a)for x, y in pairwise(l):print"%d + %d = %d"%(x, y, x + y)
Lub bardziej ogólnie:
from itertools import izip
def grouped(iterable, n):"s -> (s0,s1,s2,...sn-1), (sn,sn+1,sn+2,...s2n-1), (s2n,s2n+1,s2n+2,...s3n-1), ..."return izip(*[iter(iterable)]*n)for x, y in grouped(l,2):print"%d + %d = %d"%(x, y, x + y)
W Pythonie 3 możesz zastąpić izipgo wbudowaną zip()funkcją i upuścićimport .
Wszystko kredytowej Martineau na jego odpowiedź na moje pytanie , znalazłem to być bardzo skuteczna, ponieważ tylko iteracje raz na listę i nie tworzy żadnych zbędnych list w procesie.
Uwaga : nie należy tego mylić zpairwise przepisem we własnej itertoolsdokumentacji Pythona , która daje wynik s -> (s0, s1), (s1, s2), (s2, s3), ..., jak wskazał @lazyr w komentarzach.
Mały dodatek dla tych, którzy chcieliby sprawdzić typ za pomocą mypy w Pythonie 3:
from typing importIterable,Tuple,TypeVar
T =TypeVar("T")def grouped(iterable:Iterable[T], n=2)->Iterable[Tuple[T,...]]:"""s -> (s0,s1,s2,...sn-1), (sn,sn+1,sn+2,...s2n-1), ..."""return zip(*[iter(iterable)]* n)
Nie należy mylić z funkcją parowania sugerowaną w sekcji receptur itertools , która dajes -> (s0,s1), (s1,s2), (s2, s3), ...
Lauritz V. Thaulow
1
Robi to inaczej. Twoja wersja daje tylko połowę liczby par w porównaniu do itertoolsfunkcji receptury o tej samej nazwie. Oczywiście twoje jest szybsze ...
Sven Marnach
Co? Twoja funkcja i funkcja, o której mówiłem, robią różne rzeczy i taki był sens mojego komentarza.
Lauritz V. Thaulow
5
BĄDŹ OSTROŻNY! Korzystanie z tych funkcji stwarza ryzyko, że nie będziesz iterował ostatnich elementów iteracji. Przykład: lista (pogrupowane ([1,2,3], 2)) >>> [(1, 2)] .. kiedy można się spodziewać [(1,2), (3,)]
egafni
4
@ Erik49: W przypadku określonym w pytaniu nie ma sensu mieć krotki „niekompletnej”. Jeśli chcesz dołączyć niepełną krotkę, możesz użyć izip_longest()zamiast izip(). Np .: list(izip_longest(*[iter([1, 2, 3])]*2, fillvalue=0))-> [(1, 2), (3, 0)]. Mam nadzieję że to pomoże.
Johnsyweb
191
Cóż, potrzebujesz krotkę 2 elementów, więc
data =[1,2,3,4,5,6]for i,k in zip(data[0::2], data[1::2]):print str(i),'+', str(k),'=', str(i+k)
Gdzie:
data[0::2] oznacza tworzenie podzbioru kolekcji elementów, które (index % 2 == 0)
zip(x,y) tworzy kolekcję krotek z kolekcji xiy tych samych elementów indeksu.
Można to również rozszerzyć, jeśli wymagane są więcej niż dwa elementy. Na przykładfor i, j, k in zip(data[0::3], data[1::3], data[2::3]):
lifebalance
19
O wiele czystsze niż pobieranie importu i definiowanie funkcji!
kmarsh
7
@kmarsh: Ale działa to tylko na sekwencjach, funkcja działa na każdym iterowalnym; i to wykorzystuje dodatkowe miejsce O (N), funkcja nie; z drugiej strony jest to generalnie szybsze. Istnieją dobre powody, aby wybrać jedno lub drugie; banie się importnie jest jednym z nich.
abarnert
77
>>> l =[1,2,3,4,5,6]>>> zip(l,l[1:])[(1,2),(2,3),(3,4),(4,5),(5,6)]>>> zip(l,l[1:])[::2][(1,2),(3,4),(5,6)]>>>[a+b for a,b in zip(l,l[1:])[::2]][3,7,11]>>>["%d + %d = %d"%(a,b,a+b)for a,b in zip(l,l[1:])[::2]]['1 + 2 = 3','3 + 4 = 7','5 + 6 = 11']
To nie działa na Python-3.6.0, ale nadal działa na Python-2.7.10
Hamid
6
@HamidRohani zipzwraca zipobiekt w Pythonie 3, który nie podlega indeksowi. Najpierw należy go przekonwertować na sekwencję ( list, tupleitd.), Ale „niedziałanie” jest trochę rozciągnięte.
vaultah
58
Proste rozwiązanie.
l = [1, 2, 3, 4, 5, 6]
dla i w zakresie (0, len (l), 2):
print str (l [i]), '+', str (l [i + 1]), '=', str (l [i] + l [i + 1])
co jeśli twoja lista nie jest równa, a chcesz po prostu pokazać ostatnią cyfrę taką, jaka jest?
Hans de Jong
@HansdeJong cię nie dostał. Proszę wyjaśnić trochę więcej.
taskinoor
2
Dzięki. Już wymyśliłem, jak to zrobić. Problem polegał na tym, że jeśli masz listę, która nie zawiera nawet liczby, otrzyma błąd indeksu. Rozwiązano to za pomocą: z wyjątkiem:
Hansa de Jonga
Lub ((l[i], l[i+1])for i in range(0, len(l), 2))dla generatora, można go łatwo modyfikować dla dłuższych krotek.
Basel Shishani,
44
Chociaż wszystkie użyte odpowiedzi zipsą poprawne, uważam, że samodzielne wdrożenie funkcji prowadzi do bardziej czytelnego kodu:
def pairwise(it):
it = iter(it)whileTrue:try:yield next(it), next(it)exceptStopIteration:# no more elements in the iteratorreturn
W it = iter(it)części zapewnia, że itw rzeczywistości jest iterator, a nie tylko iterable. Jeśli itjest już iteratorem, linia ta nie ma op-op.
To rozwiązanie pozwala na uogólnienie na rozmiar krotek> 2
guilloptero
1
To rozwiązanie działa również, jeśli itjest tylko iteratorem, a nie iteracją. Inne rozwiązania wydają się polegać na możliwości utworzenia dwóch niezależnych iteratorów dla sekwencji.
Podoba mi się, że pozwala uniknąć potrojenia wykorzystania pamięci jako przyjętej odpowiedzi.
Kentzo
Nie działa to dobrze z forpętlami w Pythonie 3.5+ ze względu na PEP 479 , który zastępuje wszelkie StopIterationpodniesione w generatorze przez RuntimeError.
sidney,
28
Mam nadzieję, że będzie to jeszcze bardziej elegancki sposób.
a =[1,2,3,4,5,6]
zip(a[::2], a[1::2])[(1,2),(3,4),(5,6)]
Jeśli jesteś zainteresowany wydajnością, zrobiłem mały test porównawczy (używając mojej biblioteki simple_benchmark) w celu porównania wydajności rozwiązań i załączyłem funkcję z jednego z moich pakietów:iteration_utilities.grouper
from iteration_utilities import grouper
import matplotlib as mpl
from simple_benchmark importBenchmarkBuilder
bench =BenchmarkBuilder()@bench.add_function()defJohnsyweb(l):def pairwise(iterable):"s -> (s0, s1), (s2, s3), (s4, s5), ..."
a = iter(iterable)return zip(a, a)for x, y in pairwise(l):pass@bench.add_function()defMargus(data):for i, k in zip(data[0::2], data[1::2]):pass@bench.add_function()def pyanon(l):
list(zip(l,l[1:]))[::2]@bench.add_function()def taskinoor(l):for i in range(0, len(l),2):
l[i], l[i+1]@bench.add_function()def mic_e(it):def pairwise(it):
it = iter(it)whileTrue:try:yield next(it), next(it)exceptStopIteration:returnfor a, b in pairwise(it):pass@bench.add_function()defMSeifert(it):for item1, item2 in grouper(it,2):pass
bench.use_random_lists_as_arguments(sizes=[2**i for i in range(1,20)])
benchmark_result = bench.run()
mpl.rcParams['figure.figsize']=(8,10)
benchmark_result.plot_both(relative_to=MSeifert)
Więc jeśli chcesz najszybszego rozwiązania bez zewnętrznych zależności, prawdopodobnie powinieneś po prostu zastosować podejście podane przez Johnysweba (w momencie pisania jest to najbardziej pozytywna i akceptowana odpowiedź).
Jeśli nie przeszkadza ci dodatkowa zależność, to grouperod iteration_utilitiesbędzie prawdopodobnie nieco szybsze.
Dodatkowe przemyślenia
Niektóre podejścia mają pewne ograniczenia, które nie zostały tutaj omówione.
Na przykład kilka rozwiązań działa tylko dla sekwencji (tj. List, ciągów itp.), Na przykład rozwiązania Margus / pyanon / taskinoor, które korzystają z indeksowania, podczas gdy inne rozwiązania działają na dowolnej iterowalnej (to znaczy sekwencje i generatorach, iteratorach), takim jak Johnysweb / mic_e / my solutions.
Następnie Johnysweb dostarczył również rozwiązanie, które działa dla rozmiarów innych niż 2, podczas gdy inne odpowiedzi nie (ok iteration_utilities.grouper pozwala również ustawić liczbę elementów na „grupę”).
Następnie pojawia się pytanie, co powinno się stać, jeśli na liście znajduje się nieparzysta liczba elementów. Czy pozostały element należy odrzucić? Czy listę należy uzupełnić, aby była równa? Czy pozostały element powinien zostać zwrócony jako pojedynczy? Druga odpowiedź nie odnosi się bezpośrednio do tego punktu, jednak jeśli niczego nie przeoczyłem, wszyscy stosują podejście, zgodnie z którym pozostały element powinien zostać odrzucony (z wyjątkiem odpowiedzi Taskinoors - to faktycznie spowoduje wyjątek).
Dzięki grouperniemu możesz zdecydować, co chcesz zrobić:
zip(*iterable) zwraca krotkę z kolejnym elementem każdej iterowalnej.
l[::2] zwraca pierwszy, trzeci, piąty itd. element listy: pierwszy dwukropek wskazuje, że wycinek zaczyna się na początku, ponieważ nie ma za nim liczby, drugi dwukropek jest potrzebny tylko wtedy, gdy chcesz „kroku w wycinku” „(w tym przypadku 2).
l[1::2]robi to samo, ale zaczyna się w drugim elemencie list, więc zwraca drugi, czwarty, szósty itd. element oryginalnej listy.
l =[1,2,3,4,5,6]def divideByN(data, n):return[data[i*n :(i+1)*n]for i in range(len(data)//n)]>>>print(divideByN(l,2))[[1,2],[3,4],[5,6]]>>>print(divideByN(l,3))[[1,2,3],[4,5,6]]
lst =[1,2,3,4,5,6][(lst[i], lst[i+1])for i,_ in enumerate(lst[:-1])]>>>[(1,2),(2,3),(3,4),(4,5),(5,6)][i for i in zip(*[iter(lst)]*2)]>>>[(1,2),(3,4),(5,6)]
Używając pisania, aby zweryfikować dane za pomocą narzędzia do analizy statycznej mypy :
from typing importIterator,Any,Iterable,TypeVar,Tuple
T_ =TypeVar('T_')Pairs_Iter=Iterator[Tuple[T_, T_]]def legs(iterable:Iterator[T_])->Pairs_Iter:
begin = next(iterable)for end in iterable:yield begin, end
begin = end
jest to przydatne, jeśli twoja tablica jest a i chcesz iterować po niej parami. Aby wykonać iterację na trojaczkach lub więcej, wystarczy zmienić polecenie krokowe „zakres”, na przykład:
[(a[i],a[i+1],a[i+2])for i in range(0,len(a),3)]
(musisz poradzić sobie z nadmiarem wartości, jeśli długość tablicy i stopień nie pasują)
Tutaj możemy mieć alt_elemmetodę, która może pasować do twojej pętli for.
def alt_elem(list, index=2):for i, elem in enumerate(list, start=1):ifnot i % index:yield tuple(list[i-index:i])
a = range(10)for index in[2,3,4]:print("With index: {0}".format(index))for i in alt_elem(a, index):print(i)
Wynik:
With index:2(0,1)(2,3)(4,5)(6,7)(8,9)With index:3(0,1,2)(3,4,5)(6,7,8)With index:4(0,1,2,3)(4,5,6,7)
Uwaga: powyższe rozwiązanie może nie być wydajne, biorąc pod uwagę operacje wykonywane w func.
Odpowiedzi:
Potrzebujesz implementacji
pairwise()
(lubgrouped()
).W przypadku Python 2:
Lub bardziej ogólnie:
W Pythonie 3 możesz zastąpić
izip
go wbudowanązip()
funkcją i upuścićimport
.Wszystko kredytowej Martineau na jego odpowiedź na moje pytanie , znalazłem to być bardzo skuteczna, ponieważ tylko iteracje raz na listę i nie tworzy żadnych zbędnych list w procesie.
Uwaga : nie należy tego mylić z
pairwise
przepisem we własnejitertools
dokumentacji Pythona , która daje wyniks -> (s0, s1), (s1, s2), (s2, s3), ...
, jak wskazał @lazyr w komentarzach.Mały dodatek dla tych, którzy chcieliby sprawdzić typ za pomocą mypy w Pythonie 3:
źródło
s -> (s0,s1), (s1,s2), (s2, s3), ...
itertools
funkcji receptury o tej samej nazwie. Oczywiście twoje jest szybsze ...izip_longest()
zamiastizip()
. Np .:list(izip_longest(*[iter([1, 2, 3])]*2, fillvalue=0))
->[(1, 2), (3, 0)]
. Mam nadzieję że to pomoże.Cóż, potrzebujesz krotkę 2 elementów, więc
Gdzie:
data[0::2]
oznacza tworzenie podzbioru kolekcji elementów, które(index % 2 == 0)
zip(x,y)
tworzy kolekcję krotek z kolekcji xiy tych samych elementów indeksu.źródło
for i, j, k in zip(data[0::3], data[1::3], data[2::3]):
import
nie jest jednym z nich.źródło
zip
zwracazip
obiekt w Pythonie 3, który nie podlega indeksowi. Najpierw należy go przekonwertować na sekwencję (list
,tuple
itd.), Ale „niedziałanie” jest trochę rozciągnięte.Proste rozwiązanie.
źródło
((l[i], l[i+1])for i in range(0, len(l), 2))
dla generatora, można go łatwo modyfikować dla dłuższych krotek.Chociaż wszystkie użyte odpowiedzi
zip
są poprawne, uważam, że samodzielne wdrożenie funkcji prowadzi do bardziej czytelnego kodu:W
it = iter(it)
części zapewnia, żeit
w rzeczywistości jest iterator, a nie tylko iterable. Jeśliit
jest już iteratorem, linia ta nie ma op-op.Stosowanie:
źródło
it
jest tylko iteratorem, a nie iteracją. Inne rozwiązania wydają się polegać na możliwości utworzenia dwóch niezależnych iteratorów dla sekwencji.for
pętlami w Pythonie 3.5+ ze względu na PEP 479 , który zastępuje wszelkieStopIteration
podniesione w generatorze przezRuntimeError
.Mam nadzieję, że będzie to jeszcze bardziej elegancki sposób.
źródło
Jeśli jesteś zainteresowany wydajnością, zrobiłem mały test porównawczy (używając mojej biblioteki
simple_benchmark
) w celu porównania wydajności rozwiązań i załączyłem funkcję z jednego z moich pakietów:iteration_utilities.grouper
Więc jeśli chcesz najszybszego rozwiązania bez zewnętrznych zależności, prawdopodobnie powinieneś po prostu zastosować podejście podane przez Johnysweba (w momencie pisania jest to najbardziej pozytywna i akceptowana odpowiedź).
Jeśli nie przeszkadza ci dodatkowa zależność, to
grouper
oditeration_utilities
będzie prawdopodobnie nieco szybsze.Dodatkowe przemyślenia
Niektóre podejścia mają pewne ograniczenia, które nie zostały tutaj omówione.
Na przykład kilka rozwiązań działa tylko dla sekwencji (tj. List, ciągów itp.), Na przykład rozwiązania Margus / pyanon / taskinoor, które korzystają z indeksowania, podczas gdy inne rozwiązania działają na dowolnej iterowalnej (to znaczy sekwencje i generatorach, iteratorach), takim jak Johnysweb / mic_e / my solutions.
Następnie Johnysweb dostarczył również rozwiązanie, które działa dla rozmiarów innych niż 2, podczas gdy inne odpowiedzi nie (ok
iteration_utilities.grouper
pozwala również ustawić liczbę elementów na „grupę”).Następnie pojawia się pytanie, co powinno się stać, jeśli na liście znajduje się nieparzysta liczba elementów. Czy pozostały element należy odrzucić? Czy listę należy uzupełnić, aby była równa? Czy pozostały element powinien zostać zwrócony jako pojedynczy? Druga odpowiedź nie odnosi się bezpośrednio do tego punktu, jednak jeśli niczego nie przeoczyłem, wszyscy stosują podejście, zgodnie z którym pozostały element powinien zostać odrzucony (z wyjątkiem odpowiedzi Taskinoors - to faktycznie spowoduje wyjątek).
Dzięki
grouper
niemu możesz zdecydować, co chcesz zrobić:źródło
Użyj razem poleceń
zip
iiter
:Uważam, że to rozwiązanie
iter
jest dość eleganckie:Który znalazłem w dokumentacji zip Python 3 .
Aby uogólnić na
N
elementy jednocześnie:źródło
zip(*iterable)
zwraca krotkę z kolejnym elementem każdej iterowalnej.l[::2]
zwraca pierwszy, trzeci, piąty itd. element listy: pierwszy dwukropek wskazuje, że wycinek zaczyna się na początku, ponieważ nie ma za nim liczby, drugi dwukropek jest potrzebny tylko wtedy, gdy chcesz „kroku w wycinku” „(w tym przypadku 2).l[1::2]
robi to samo, ale zaczyna się w drugim elemencie list, więc zwraca drugi, czwarty, szósty itd. element oryginalnej listy.źródło
[number::number]
działa składnia. pomocne dla tych, którzy często nie używają PythonaZ rozpakowaniem:
źródło
Dla każdego może to pomóc, oto rozwiązanie podobnego problemu, ale z nakładającymi się parami (zamiast wzajemnie wykluczających się par).
Z dokumentacji itertools Python :
Lub bardziej ogólnie:
źródło
możesz użyć pakietu more_itertools .
źródło
Muszę podzielić listę przez liczbę i tak ustawić.
źródło
Można to zrobić na wiele sposobów. Na przykład:
źródło
Pomyślałem, że to dobre miejsce, by podzielić się moim uogólnieniem na n> 2, które jest po prostu przesuwanym oknem nad iteracją:
źródło
Tytuł tego pytania jest mylący, wydaje się, że szukasz kolejnych par, ale jeśli chcesz iterować zestaw wszystkich możliwych par, to zadziała:
źródło
Używając pisania, aby zweryfikować dane za pomocą narzędzia do analizy statycznej mypy :
źródło
Uproszczone podejście:
jest to przydatne, jeśli twoja tablica jest a i chcesz iterować po niej parami. Aby wykonać iterację na trojaczkach lub więcej, wystarczy zmienić polecenie krokowe „zakres”, na przykład:
(musisz poradzić sobie z nadmiarem wartości, jeśli długość tablicy i stopień nie pasują)
źródło
Tutaj możemy mieć
alt_elem
metodę, która może pasować do twojej pętli for.Wynik:
Uwaga: powyższe rozwiązanie może nie być wydajne, biorąc pod uwagę operacje wykonywane w func.
źródło
źródło