Yanıtlar:
Bir pairwise()
(veya grouped()
) uygulamaya ihtiyacınız var .
Python 2 için:
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)
Veya daha genel olarak:
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)
Python 3'te, izip
yerleşikzip()
işlevle ve simgesini bırakabilirsiniz import
.
Tüm kredi Martineau için onun cevabını için sorumu , ben sadece liste üzerinde bir kez dolaşır ve süreç içinde gereksiz listeleri yaratmaz olarak çok verimli olması için bu bulduk.
NB : Bu ile karıştırılmamalıdır pairwise
tarifi Python'un kendi içinde itertools
belgeler , verimleri s -> (s0, s1), (s1, s2), (s2, s3), ...
ile sivri out gibi, @lazyr , yorumlarda .
Python 3'te mypy ile tip kontrolü yapmak isteyenler için küçük bir ek :
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), ...
itertools
, aynı ada sahip tarif işlevine kıyasla çift sayısının yalnızca yarısını verir . Tabii seninki daha hızlı ...
izip_longest()
yerine kullanabilirsiniz izip()
. Örneğin: list(izip_longest(*[iter([1, 2, 3])]*2, fillvalue=0))
-> [(1, 2), (3, 0)]
. Bu yardımcı olur umarım.
Peki 2 öğeden oluşan bir gruba ihtiyacınız var, yani
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)
Nerede:
data[0::2]
şu öğelerin alt küme koleksiyonunu oluşturmak anlamına gelir: (index % 2 == 0)
zip(x,y)
x ve y koleksiyonlarından aynı indeks elemanlarından bir grup koleksiyonu oluşturur.for i, j, k in zip(data[0::3], data[1::3], data[2::3]):
import
bunlardan biri değil.
>>> 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']
zip
bir zip
nesne döndürür . İlk önce bir sekansa ( list
, tuple
vb.) Dönüştürülmesi gerekir , ancak "çalışmıyor" biraz esnektir.
Basit bir çözüm.
l = [1, 2, 3, 4, 5, 6] (0, len (l), 2) aralığında i için: baskı 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))
bir jeneratör için, daha uzun tuples için kolayca değiştirilebilir.
Tüm cevaplar zip
doğru olsa da , işlevselliği kendiniz uygulamanın daha okunabilir koda götürdüğünü görüyorum:
def pairwise(it):
it = iter(it)
while True:
try:
yield next(it), next(it)
except StopIteration:
# no more elements in the iterator
return
it = iter(it)
Bölüm olmasını sağlar it
aslında bir yineleyici değil, sadece bir iterable olduğunu. Eğer it
zaten Yineleyicinin, bu hat no-operasyon.
Kullanımı:
for a, b in pairwise([0, 1, 2, 3, 4, 5]):
print(a + b)
it
sadece bir yineleyici ve yinelenebilir değilse de çalışır . Diğer çözümler, dizi için iki bağımsız yineleyici oluşturma olasılığına güveniyor gibi görünüyor.
Umarım bunu yapmanın daha zarif bir yolu olacaktır.
a = [1,2,3,4,5,6]
zip(a[::2], a[1::2])
[(1, 2), (3, 4), (5, 6)]
Performansla ilgileniyorsanız simple_benchmark
, çözümlerin performansını karşılaştırmak için küçük bir kıyaslama yaptım (kütüphanemi kullanarak ) ve paketlerimden birinden bir işlev ekledim: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)
Dış bağımlılıklar olmadan en hızlı çözümü istiyorsanız, muhtemelen sadece Johnysweb tarafından verilen yaklaşımı kullanmalısınız (yazarken en doğru ve kabul edilen cevaptır).
Sonra ek bağımlılık sakıncası yoksa grouper
geleniteration_utilities
muhtemelen biraz daha hızlı olacaktır.
Bazı yaklaşımların burada tartışılmayan bazı kısıtlamaları vardır.
Örneğin, birkaç çözüm sadece sekanslar (listeler, dizeler vb.) İçin çalışır, örneğin diğer çözümler herhangi bir yinelenebilir (yani sekanslar ve sekanslar) üzerinde çalışırken indeksleme kullanan Margus / pyanon / taskinoor çözümleri Johnysweb gibi jeneratör, iterators) / mic_e / çözümlerim.
Daha sonra Johnysweb ayrıca 2'den farklı boyutlarda çalışan bir çözüm sunarken, diğer cevaplar işe yaramaz (tamam, aynı iteration_utilities.grouper
zamanda eleman sayısının "grup" olarak ayarlanmasına da izin verir).
Listede tek sayıda eleman varsa ne olması gerektiği hakkında da bir soru var. Kalan eşya reddedilmeli mi? Liste, boyutunun eşit olması için doldurulmalı mıdır? Kalan ürün tek olarak iade edilmeli mi? Diğer cevap bu noktayı doğrudan ele almaz, ancak hiçbir şeyi göz ardı etmediysem, hepsi kalan öğenin reddedilmesi gerektiği yaklaşımını izler (taskinoors cevabı hariç - bu gerçekten bir istisna yaratacaktır).
İle grouper
ne yapmak istediğinize karar verebilirsiniz:
>>> 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)]
zip
Ve iter
komutlarını birlikte kullanın :
Bu çözümü iter
oldukça zarif kullanarak buluyorum :
it = iter(l)
list(zip(it, it))
# [(1, 2), (3, 4), (5, 6)]
Hangi Python 3 zip belgelerinde buldum .
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
N
Bir defada elemanlara genelleme yapmak için :
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)
her bir yinelenebilir öğenin bir sonraki elemanı olan bir demet döndürür.
l[::2]
listenin 1., 3., 5. vb. öğelerini döndürür: ilk iki nokta, dilimin başında başladığını gösterir, çünkü arkasında sayı yok, ikinci iki nokta yalnızca dilimde bir 'adım istiyorsanız '(bu durumda 2).
l[1::2]
aynı şeyi yapar ancak listenin ikinci öğesinde başlar, böylece orijinal listenin 2., 4., 6. vb. öğelerini döndürür .
[number::number]
sözdiziminin nasıl çalıştığını açıklamak için . sık sık python kullanmayanlar için yararlı
Ambalajdan çıkarıldığında:
l = [1,2,3,4,5,6]
while l:
i, k, *l = l
print(str(i), '+', str(k), '=', str(i+k))
Herkes için yardımcı olabilir, burada benzer bir soruna ancak üst üste gelen çiftlere (karşılıklı olarak ayrı çiftler yerine) bir çözüm var.
Python itertools belgelerinden :
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)
Veya daha genel olarak:
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)
more_itertools paketini kullanabilirsiniz .
import more_itertools
lst = range(1, 7)
for i, j in more_itertools.chunked(lst, 2):
print(f'{i} + {j} = {i+j}')
Bir listeyi bir sayıya bölmem ve böyle sabitlemem gerekiyor.
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]]
Bunu yapmanın birçok yolu var. Örneğin:
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)]
Mypy statik analiz aracını kullanarak verileri doğrulayabilmeniz için yazmayı kullanma :
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
Basit bir yaklaşım:
[(a[i],a[i+1]) for i in range(0,len(a),2)]
diziniz a ise ve üzerinde çiftler halinde yineleme yapmak istiyorsanız bu yararlıdır. Üçüz veya daha fazlasında yineleme yapmak için sadece "aralık" adım komutunu değiştirin, örneğin:
[(a[i],a[i+1],a[i+2]) for i in range(0,len(a),3)]
(dizi uzunluğunuz ve adımınız uymuyorsa aşırı değerlerle uğraşmanız gerekir)
Burada alt_elem
for döngüsü için uygun bir yöntem olabilir.
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)
Çıktı:
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)
Not: Yukarıdaki çözüm işlevde gerçekleştirilen işlemler düşünüldüğünde etkili olmayabilir.