बस यह दिखाने के लिए कि आप itertoolsव्यंजनों को कैसे जोड़ सकते हैं , मैं नुस्खा का उपयोग करते हुए pairwiseसीधे नुस्खा में वापस ला रहा हूं :windowconsume
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 - 1iterators। consumeप्रत्येक isliceपुनरावृत्त को लपेटने के बजाय का उपयोग करना थोड़ा तेज है (पर्याप्त रूप से बड़े पुनरावृत्तियों के लिए) क्योंकि आप केवल चरण के isliceदौरान रैपिंग ओवरहेड का भुगतान करते हैं consume, न कि प्रत्येक विंडो-एड मान को निकालने की प्रक्रिया के दौरान (इसलिए यह बाध्य है n, न कि मदों की संख्या।iterable )।
प्रदर्शन-वार, कुछ अन्य समाधानों की तुलना में, यह बहुत अच्छा है (और किसी अन्य समाधान की तुलना में बेहतर है जिसे मैंने तराजू के रूप में परीक्षण किया है)। ipython %timeitजादू का उपयोग करके पायथन 3.5.0, लिनक्स x86-64 पर परीक्षण किया गया ।
kindall है dequeसमाधान का उपयोग करके, प्रदर्शन / शुद्धता के लिए बदलाव isliceएक घर लुढ़का जनरेटर अभिव्यक्ति के बजाय और जिसके परिणामस्वरूप लंबाई परीक्षण तो यह परिणाम नहीं करता है जब iterable खिड़की से भी कम है, साथ ही गुजर maxlenकी dequepositionally बजाय कीवर्ड द्वारा (छोटे इनपुट के लिए एक आश्चर्यजनक अंतर बनाता है):
>>> %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मामले में , विशेष रूप से छोटे इनपुट के लिए जहां सेटअप ओवरहेड काम का एक सार्थक हिस्सा है:consumen 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()) यह ध्यान में असर लायक कुशल एल्गोरिदम में प्रत्येक विंडो के लिए नए मूल्य की गणना करने देखते हैं कि है निरंतर समय (भले ही विंडो आकार का)। मैंने पायथन लाइब्रेरी में इनमें से कुछ एल्गोरिदम को एक साथ एकत्रित किया है: रोलिंग ।