बस यह दिखाने के लिए कि आप itertools
व्यंजनों को कैसे जोड़ सकते हैं , मैं नुस्खा का उपयोग करते हुए pairwise
सीधे नुस्खा में वापस ला रहा हूं :window
consume
def consume(iterator, n):
"Advance the iterator n-steps ahead. If n is none, consume entirely."
# Use functions that consume iterators at C speed.
if n is None:
# feed the entire iterator into a zero-length deque
collections.deque(iterator, maxlen=0)
else:
# advance to the empty slice starting at position n
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)
# Could use enumerate(islice(iters, 1, None), 1) to avoid consume(it, 0), but that's
# slower for larger window sizes, while saving only small fixed "noop" cost
for i, it in enumerate(iters):
consume(it, i)
return zip(*iters)
window
नुस्खा के लिए के रूप में ही है pairwise
, यह सिर्फ एक तत्व "उपभोग" दूसरी पर बदलता है tee
उत्तरोत्तर पर खपत में वृद्धि के साथ एड इटरेटर n - 1
iterators। consume
प्रत्येक islice
पुनरावृत्त को लपेटने के बजाय का उपयोग करना थोड़ा तेज है (पर्याप्त रूप से बड़े पुनरावृत्तियों के लिए) क्योंकि आप केवल चरण के islice
दौरान रैपिंग ओवरहेड का भुगतान करते हैं consume
, न कि प्रत्येक विंडो-एड मान को निकालने की प्रक्रिया के दौरान (इसलिए यह बाध्य है n
, न कि मदों की संख्या।iterable
)।
प्रदर्शन-वार, कुछ अन्य समाधानों की तुलना में, यह बहुत अच्छा है (और किसी अन्य समाधान की तुलना में बेहतर है जिसे मैंने तराजू के रूप में परीक्षण किया है)। ipython
%timeit
जादू का उपयोग करके पायथन 3.5.0, लिनक्स x86-64 पर परीक्षण किया गया ।
kindall है deque
समाधान का उपयोग करके, प्रदर्शन / शुद्धता के लिए बदलाव islice
एक घर लुढ़का जनरेटर अभिव्यक्ति के बजाय और जिसके परिणामस्वरूप लंबाई परीक्षण तो यह परिणाम नहीं करता है जब iterable खिड़की से भी कम है, साथ ही गुजर maxlen
की deque
positionally बजाय कीवर्ड द्वारा (छोटे इनपुट के लिए एक आश्चर्यजनक अंतर बनाता है):
>>> %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
पिछले अनुकूलित किंडल सॉल्यूशन के रूप में भी, लेकिन प्रत्येक के साथ जनरेटर के काम करने के परिणाम में yield win
बदलाव के yield tuple(win)
बिना सभी संग्रहीत परिणाम वास्तव में सबसे हाल के परिणाम (इस परिदृश्य में अन्य सभी उचित समाधान सुरक्षित हैं) का एक दृश्य है, और tuple=tuple
फ़ंक्शन परिभाषा में जोड़कर के उपयोग को स्थानांतरित करने tuple
से B
में LEGB
करने के लिए 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
ऊपर दिखाए गए समाधान:
>>> %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
उसी के रूप में consume
, लेकिन रनटाइम को कम करने के लिए फ़ंक्शन कॉल और परीक्षण से बचने के else
मामले में , विशेष रूप से छोटे इनपुट के लिए जहां सेटअप ओवरहेड काम का एक सार्थक हिस्सा है:consume
n is None
>>> %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
(साइड-नोट: pairwise
उस पर एक वेरिएंट tee
जो नेस्टेड tee
ऑब्जेक्ट बनाने के लिए 2 के डिफ़ॉल्ट तर्क के साथ बार-बार उपयोग करता है , इसलिए किसी भी दिए गए इटरेटर को केवल एक बार उन्नत किया जाता है, स्वतंत्र रूप से बढ़ती हुई संख्या का उपभोग नहीं किया जाता है, जैसा कि MrDrFenner का जवाब गैर- इनबिल्ड के समान है। consume
और consume
सभी परीक्षणों पर इनबिल्ड की तुलना में धीमा है , इसलिए मैंने इसे संक्षिप्तता के लिए उन परिणामों को छोड़ दिया है)।
जैसा कि आप देख सकते हैं, यदि आपको कॉल करने वाले को परिणाम स्टोर करने की आवश्यकता की संभावना के बारे में परवाह नहीं है , तो किंडल के समाधान का मेरा अनुकूलित संस्करण "बड़े चलने योग्य, छोटे खिड़की के आकार के मामले" को छोड़कर अधिकांश समयconsume
जीतता है (जहां इनबिल्ड जीत होती है ); iterable size बढ़ने पर यह जल्दी खराब हो जाता है, जबकि खिड़की का आकार बढ़ने पर बिलकुल भी नीचा नहीं होता (iterable size बढ़ने के लिए हर दूसरा घोल धीरे-धीरे कम होता जाता है, लेकिन खिड़की के आकार में बढ़ोतरी भी घटती है)। इसे "रैपिंग टपल" केस के लिए रैप करके भी अनुकूलित किया जा सकता है map(tuple, ...)
, जो फंक्शन में ट्यूपलिंग लगाने की तुलना में थोड़ा धीमा चलता है, लेकिन यह तुच्छ है (1-5% अधिक समय लगता है) और आपको तेज चलने की सुविधा देता है जब आप बर्दाश्त कर सकते हैं बार-बार एक ही मूल्य लौटाने।
यदि आपको संग्रहित किए जाने वाले रिटर्न के खिलाफ सुरक्षा की आवश्यकता है, तो consume
सभी पर सबसे छोटे इनपुट आकार (गैर-इनलाइन consume
थोड़ा धीमा लेकिन समान रूप से स्केलिंग के साथ) में जीतता है । deque
और tupling आधारित समाधान जीत केवल छोटी से छोटी जानकारी के लिए, छोटे सेटअप लागत की वजह से के लिए, और लाभ छोटा है, जब यह चलने योग्य हो जाता है तो यह बुरी तरह खराब हो जाता है।
रिकॉर्ड, kindall के समाधान के लिए अनुकूलित संस्करण के लिए yield
रों tuple
रों मैं इस्तेमाल किया गया था:
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)
tuple
फंक्शन डेफिनिशन लाइन और tuple
प्रत्येक yield
का उपयोग तेजी से लेकिन कम सुरक्षित संस्करण प्राप्त करने के लिए कैशिंग को छोड़ दें ।
sum()
याmax()
) यह ध्यान में असर लायक कुशल एल्गोरिदम में प्रत्येक विंडो के लिए नए मूल्य की गणना करने देखते हैं कि है निरंतर समय (भले ही विंडो आकार का)। मैंने पायथन लाइब्रेरी में इनमें से कुछ एल्गोरिदम को एक साथ एकत्रित किया है: रोलिंग ।