Odpowiedzi:
Potrzebujesz implementacji pairwise()(lub grouped()).
W przypadku Python 2:
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 import Iterable, 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)
s -> (s0,s1), (s1,s2), (s2, s3), ...
itertoolsfunkcji receptury o tej samej nazwie. Oczywiście twoje jest szybsze ...
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.
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.for i, j, k in zip(data[0::3], data[1::3], data[2::3]):
importnie jest jednym z nich.
>>> 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']
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.
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])
((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 zipsą poprawne, uważam, że samodzielne wdrożenie funkcji prowadzi do bardziej czytelnego kodu:
def pairwise(it):
it = iter(it)
while True:
try:
yield next(it), next(it)
except StopIteration:
# no more elements in the iterator
return
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.
Stosowanie:
for a, b in pairwise([0, 1, 2, 3, 4, 5]):
print(a + b)
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.
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 import BenchmarkBuilder
bench = BenchmarkBuilder()
@bench.add_function()
def Johnsyweb(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()
def Margus(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)
while True:
try:
yield next(it), next(it)
except StopIteration:
return
for a, b in pairwise(it):
pass
@bench.add_function()
def MSeifert(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.
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ć:
>>> from iteration_utilities import grouper
>>> list(grouper([1, 2, 3], 2)) # as single
[(1, 2), (3,)]
>>> list(grouper([1, 2, 3], 2, truncate=True)) # ignored
[(1, 2)]
>>> list(grouper([1, 2, 3], 2, fillvalue=None)) # padded
[(1, 2), (3, None)]
Użyj razem poleceń zipi iter:
Uważam, że to rozwiązanie iterjest dość eleganckie:
it = iter(l)
list(zip(it, it))
# [(1, 2), (3, 4), (5, 6)]
Który znalazłem w dokumentacji zip Python 3 .
it = iter(l)
print(*(f'{u} + {v} = {u+v}' for u, v in zip(it, it)), sep='\n')
# 1 + 2 = 3
# 3 + 4 = 7
# 5 + 6 = 11
Aby uogólnić na Nelementy jednocześnie:
N = 2
list(zip(*([iter(l)] * N)))
# [(1, 2), (3, 4), (5, 6)]
for (i, k) in zip(l[::2], l[1::2]):
print i, "+", k, "=", i+k
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.
[number::number]działa składnia. pomocne dla tych, którzy często nie używają Pythona
Z rozpakowaniem:
l = [1,2,3,4,5,6]
while l:
i, k, *l = l
print(str(i), '+', str(k), '=', str(i+k))
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 :
from itertools import izip
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = tee(iterable)
next(b, None)
return izip(a, b)
Lub bardziej ogólnie:
from itertools import izip
def groupwise(iterable, n=2):
"s -> (s0,s1,...,sn-1), (s1,s2,...,sn), (s2,s3,...,sn+1), ..."
t = tee(iterable, n)
for i in range(1, n):
for j in range(0, i):
next(t[i], None)
return izip(*t)
możesz użyć pakietu more_itertools .
import more_itertools
lst = range(1, 7)
for i, j in more_itertools.chunked(lst, 2):
print(f'{i} + {j} = {i+j}')
Muszę podzielić listę przez liczbę i tak ustawić.
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]]
Można to zrobić na wiele sposobów. Na przykład:
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)]
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ą:
def sliding_window(iterable, n):
its = [ itertools.islice(iter, i, None)
for i, iter
in enumerate(itertools.tee(iterable, n)) ]
return itertools.izip(*its)
Używając pisania, aby zweryfikować dane za pomocą narzędzia do analizy statycznej mypy :
from typing import Iterator, 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
Uproszczone podejście:
[(a[i],a[i+1]) for i in range(0,len(a),2)]
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):
if not 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.
a_list = [1,2,3,4,5,6]
empty_list = []
for i in range(0,len(a_list),2):
empty_list.append(a_list[i]+a_list[i+1])
print(empty_list)