Sadece itertoolstarifleri nasıl birleştirebileceğinizi göstermek pairwiseiçin, windowtarifi kullanarak tarifi mümkün olduğunca doğrudan tarife genişletiyorum consume:
def consume(iterator, n):
"Advance the iterator n-steps ahead. If n is none, consume entirely."
if n is None:
collections.deque(iterator, maxlen=0)
else:
next(islice(iterator, n, n), None)
def window(iterable, n=2):
"s -> (s0, ...,s(n-1)), (s1, ...,sn), (s2, ..., s(n+1)), ..."
iters = tee(iterable, n)
for i, it in enumerate(iters):
consume(it, i)
return zip(*iters)
windowTarifi aynıdır pairwisesadece ikinci tek eleman "tüketmek" yerine, teekademeli üzerinde tüketir artan -ed yineleyici n - 1Yineleyicilerin. consumeHer yineleyiciyi sarmak yerine kullanmak islice, marjinal olarak daha hızlıdır (yeterince büyük yinelemeler için), çünkü her pencereli değeri ayıklama işlemi sırasında değil, yalnızca aşama islicesırasında sarma ek yükünü ödersiniz consume(bu nedenle n, içindeki öğelerin sayısı ile sınırlı değildir)iterable ).
Performans açısından, diğer bazı çözümlerle karşılaştırıldığında, bu oldukça iyi (ve ölçeklenirken test ettiğim diğer çözümlerden daha iyi). ipython %timeitSihir kullanılarak Python 3.5.0, Linux x86-64 üzerinde test edilmiştir .
kindall bu dequeçözelti kullanılarak performansı / doğruluğu tweaked, islicebunun yerine bir ev haddelenmiş jeneratör ifade ve iterable penceresinden daha kısa olduğunda sonuç vermezse bu nedenle ortaya çıkan uzunluğu test olarak geçen maxlenbir dequepozisyon olarak yerine anahtar kelimeye göre (daha küçük girdiler için şaşırtıcı bir fark yaratır):
>>> %timeit -r5 deque(windowkindall(range(10), 3), 0)
100000 loops, best of 5: 1.87 μs per loop
>>> %timeit -r5 deque(windowkindall(range(1000), 3), 0)
10000 loops, best of 5: 72.6 μs per loop
>>> %timeit -r5 deque(windowkindall(range(1000), 30), 0)
1000 loops, best of 5: 71.6 μs per loop
Önceki uyarlanmış genel çözümle aynıdır, ancak her biri yield windeğiştirildiğinde yield tuple(win), jeneratörden alınan sonuçların depolanması, depolanan tüm sonuçlar gerçekten en son sonucun bir görünümü olmadan çalışır (bu senaryoda diğer tüm makul çözümler güvenlidir) ve tuple=tupleişlev tanımına ekleme yapılır. kullanımını taşımak için tuplegelen Biçinde LEGBiçin L:
>>> %timeit -r5 deque(windowkindalltupled(range(10), 3), 0)
100000 loops, best of 5: 3.05 μs per loop
>>> %timeit -r5 deque(windowkindalltupled(range(1000), 3), 0)
10000 loops, best of 5: 207 μs per loop
>>> %timeit -r5 deque(windowkindalltupled(range(1000), 30), 0)
1000 loops, best of 5: 348 μs per loop
consume-yukarıda gösterilen tabanlı çözüm:
>>> %timeit -r5 deque(windowconsume(range(10), 3), 0)
100000 loops, best of 5: 3.92 μs per loop
>>> %timeit -r5 deque(windowconsume(range(1000), 3), 0)
10000 loops, best of 5: 42.8 μs per loop
>>> %timeit -r5 deque(windowconsume(range(1000), 30), 0)
1000 loops, best of 5: 232 μs per loop
Aynı consumefakat inlining elsevaka consumeönlemek işlev çağrısı ve n is Nonetestin özellikle kurulum havai işin anlamlı bir parçası olan küçük girişler için, çalışma zamanı azaltmak için:
>>> %timeit -r5 deque(windowinlineconsume(range(10), 3), 0)
100000 loops, best of 5: 3.57 μs per loop
>>> %timeit -r5 deque(windowinlineconsume(range(1000), 3), 0)
10000 loops, best of 5: 40.9 μs per loop
>>> %timeit -r5 deque(windowinlineconsume(range(1000), 30), 0)
1000 loops, best of 5: 211 μs per loop
(Yan not: İç içe nesneler yapmak için 2 varsayılan argümanını tekrar tekrar pairwisekullanan bir varyant, bu nedenle herhangi bir yineleyici yalnızca bir kez geliştirilir, bağımsız olarak artan sayıda tüketilmez, MrDrFenner'ın cevabına benzer şekilde satır içi olmayanlara benzer ve tüm testlerde satır içi belirtilenden daha yavaştır , bu yüzden kısalık için bu sonuçları göz ardı ettim).teeteeconsumeconsume
Gördüğünüz gibi , arayanın sonuçları saklamaya ihtiyaç duyma olasılığını umursamıyorsanız, "büyük yinelenebilir, küçük pencere boyutu durumu" dışında (satır içi consumekazançların olduğu yerde) , kindall çözümünün optimize edilmiş sürümü çoğu zaman kazanır. ); yinelenebilir boyut arttıkça hızla küçülür, ancak pencere boyutu büyüdükçe küçülmez (diğer tüm çözümler yinelenebilir boyut artışları için daha yavaş küçülür, aynı zamanda pencere boyutu büyüdükçe küçülür). Hatta sarmalayarak "ihtiyaç demetleri" durumuna göre uyarlanabilir map(tuple, ...), bu da tupling'i işleve yerleştirmekten çok daha yavaş çalışır, ancak önemsizdir (% 1-5 daha uzun sürer) ve daha hızlı koşma esnekliğini korumanıza izin verir Tekrar tekrar aynı değeri döndürmeyi tolere edebildiğinizde.
İadelerin depolanmasına karşı güvenliğe ihtiyacınız varsa consume, en küçük girdi boyutları dışında satır içi kazanır (satır içi olmayanlar consumebiraz daha yavaştır, ancak benzer şekilde ölçeklenir). deque& Sadece nedeniyle küçük kurulum maliyetlerine en küçük girişler için esaslı çözüm kazanıyor tupling ve kazanç küçüktür; yinelenebilir süre uzadıkça kötü bir şekilde bozulur.
Kayıt, o kindall çözümünü uygun uyarlanan versiyonu için yields adlı tupleler benim kullandığım oldu:
def windowkindalltupled(iterable, n=2, tuple=tuple):
it = iter(iterable)
win = deque(islice(it, n), n)
if len(win) < n:
return
append = win.append
yield tuple(win)
for e in it:
append(e)
yield tuple(win)
Daha hızlı ancak daha az güvenli sürümü elde etmek tupleiçin işlev tanımı satırına önbelleğe almayı ve tupleher birinin kullanımını bırakın yield.
sum()veyamax()) her pencerede bir tür işlem gerçekleştirmek istiyorsanız, her pencere için yeni değeri sabit zamanda (pencere boyutundan bağımsız olarak) hesaplamak için etkili algoritmalar olduğunu unutmamak gerekir . Bu algoritmalardan bazılarını bir Python kitaplığında topladım: yuvarlanma .