2012-04-03 26 views
19

मैंने कुछ कोड बदल दिया है जो डेक का उपयोग करने के लिए एक सूची का उपयोग करता है। मैं अब इसमें फिसल नहीं सकता, क्योंकि मुझे त्रुटि मिलती है:एक डेक टुकड़ा कैसे करें?

TypeError: sequence index must be integer, not 'slice'

यहां एक आरईपीएल है जो समस्या को दिखाता है।

>>> import collections 
>>> d = collections.deque() 
>>> for i in range(3): 
...  d.append(i) 
... 
>>> d 
deque([0, 1, 2]) 
>>> d[2:] 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: sequence index must be integer, not 'slice' 

तो, क्या पाइथन में डेक में स्लाइसिंग का समर्थन करने के लिए कोई कामकाज है?

+0

@HunterMcMillen, अपनी टिप्पणी के लिए धन्यवाद:

यह मैं कैसे परीक्षण किया है। मैं प्रदर्शन के लिए 'डेक्यू' का उपयोग कर रहा हूं (वास्तव में एक गोलाकार बफर के रूप में) और इसलिए प्रत्येक चक्र की सूची में डेटा कॉपी करना आदर्श नहीं है। –

+0

रिलायंस: http: // stackoverflow।कॉम/प्रश्न/7064289/उपयोग-टुकड़ा-नोटेशन-संग्रह-डेक – georg

+0

@ thg435, क्रॉस संदर्भ के लिए धन्यवाद। मैंने त्रुटि स्ट्रिंग को गुगल किया और SO पर कुछ भी नहीं मिला, इसलिए इस नए प्रश्न को पोस्ट करना। वहां कुछ अच्छी अंतर्दृष्टि भी है। –

उत्तर

23

itertools.islice() आज़माएं।

deque_slice = collections.deque(itertools.islice(my_deque, 10, 20)) 

एक deque में अनुक्रमण शुरुआत हर बार से एक लिंक्ड सूची, इसलिए islice() दृष्टिकोण, आइटम लंघन टुकड़ा के शुरू करने के लिए निम्नलिखित की आवश्यकता है, बेहतरीन प्रदर्शन के (के रूप में यह कोडिंग की तुलना में बेहतर दे देंगे प्रत्येक तत्व के लिए एक सूचकांक ऑपरेशन)।

आप आसानी से deque सबक्लास लिख सकते हैं जो यह आपके लिए स्वचालित रूप से करता है।

class sliceable_deque(collections.deque): 
    def __getitem__(self, index): 
     if isinstance(index, slice): 
      return type(self)(itertools.islice(self, index.start, 
               index.stop, index.step)) 
     return collections.deque.__getitem__(self, index) 

ध्यान दें कि आप islice के साथ नकारात्मक सूचकांक या कदम मूल्यों का उपयोग नहीं कर सकते। इसके आसपास कोड करना संभव है, और यदि आप सबक्लास दृष्टिकोण लेते हैं तो ऐसा करने के लिए उपयुक्त हो सकता है। नकारात्मक शुरुआत या बंद करने के लिए आप बस डेक की लंबाई जोड़ सकते हैं; नकारात्मक चरण के लिए, आपको वहां कहीं reversed() फेंकने की आवश्यकता होगी। मैं इसे एक अभ्यास के रूप में छोड़ दूंगा। :-)

deque से अलग-अलग आइटमों को पुनर्प्राप्त करने का प्रदर्शन स्लाइस के लिए if परीक्षण से थोड़ा कम हो जाएगा।

class sliceable_deque(collections.deque): 
    def __getitem__(self, index): 
     try: 
      return collections.deque.__getitem__(self, index) 
     except TypeError: 
      return type(self)(itertools.islice(self, index.start, 
               index.stop, index.step)) 

बेशक वहाँ एक अतिरिक्त: जरूरत की वजह से अपवाद कार्रवाई करने के लिए टुकड़ा पथ थोड़ा कम performant बनाने की लागत में - यह एक मुद्दा है, तो आप एक EAFP पैटर्न यह कुछ हद तक कम करने के लिए उपयोग कर सकते हैं एक नियमित deque की तुलना में अभी भी फ़ंक्शन कॉल, इसलिए यदि आप वास्तव में प्रदर्शन की परवाह करते हैं, तो आप वास्तव में एक अलग slice() विधि या पसंद जोड़ना चाहते हैं।

+4

मैं लगातार आश्चर्यचकित हूं कि itertools मॉड्यूल कितना जादुई है। ऐसा लगता है कि जब भी मैं समीक्षा करता हूं, मैं इसके बारे में और अधिक सीखता रहता हूं। – jdi

+4

मेरे बड़े जाने-माने मॉड्यूल इटारटोल, functools, और संग्रह हैं। बहुत शक्ति – kindall

+0

धन्यवाद, मैं एक परिवर्तनीय लंबाई बफर पर नकारात्मक अनुक्रमण का उपयोग कर रहा था, लेकिन यह प्रति उदाहरण लंबाई तय किया गया था। इसलिए, मैंने अपने तर्क को चारों ओर फिसल दिया और प्रति उदाहरण सकारात्मक सूचकांक बना दिया। एक व्यापार जो स्मार्ट से अधिक था। – RobotHumans

8

यदि प्रदर्शन एक चिंता है, तो this answer में सुझाए गए अनुसार प्रत्यक्ष पहुंच/समझ विधि पर विचार करें। यह बहुत बड़े संग्रह पर islice की तुलना में तेजी है:

import timeit 

setup = """ 
import collections, itertools 
d = collections.deque(range(10000)) 
""" 

print timeit.timeit('list(itertools.islice(d, 9000, 9010))', setup, number=10000) 
## 0.631947040558 
print timeit.timeit('[d[i] for i in range(9000, 9010)]', setup, number=10000) 
## 0.0292208194733 

अनुसार @RaymondHettinger टिप्पणी नीचे, समझ विधि केवल बेहतर है जब स्लाइस कम कर रहे हैं। लंबे स्लाइस पर, islice दृढ़ता से जीतता है। उदाहरण के लिए, यहाँ एक 10,000 आइटम टुकड़ा करने की क्रिया के लिए समय की भरपाई के 6000 से Deque हैं:

 
offset length  islice  compr 
6000  10  400.496  46.611 
6000  50  424.600  183.988 
6000  90  432.277  237.894 
6000  130  441.289  352.383 
6000  170  431.299  404.596 
6000  210  456.405  546.503 
6000  250  448.895  575.995 
6000  290  485.802  778.294 
6000  330  483.704  781.703 
6000  370  490.904  948.501 
6000  410  500.011  875.807 
6000  450  508.213 1045.299 
6000  490  518.894 1010.203 
6000  530  530.887 1192.784 
6000  570  534.415 1151.013 
6000  610  530.887 1504.779 
6000  650  539.279 1486.802 
6000  690  536.084 1650.810 
6000  730  549.698 1454.687 
6000  770  564.909 1576.114 
6000  810  545.001 1588.297 
6000  850  564.504 1711.607 
6000  890  584.197 1760.793 
6000  930  564.480 1963.091 
6000  970  586.390 1955.199 
6000 1010  590.706 2117.491 

समझ बहुत तेजी से पहले कुछ स्लाइस करता है, लेकिन के रूप में लंबाई बढ़ता प्रदर्शन नाटकीय रूप से नीचे गिर जाता है। islice छोटे स्लाइस पर धीमा है, लेकिन इसकी औसत गति बहुत बेहतर है।

import timeit 

size = 10000 
repeats = 100 

setup = """ 
import collections, itertools 
d = collections.deque(range(%d)) 
""" % size 

print '%5s\t%5s\t%10s\t%10s' % ('offset', 'length', 'islice', 'compr') 

for offset in range(0, size - 2000, 2000): 
    for length in range(10, 2000, 40): 
     t1 = timeit.timeit('list(itertools.islice(d, %d, %d))' % (offset, offset + length), setup, number=repeats) 
     t2 = timeit.timeit('[d[i] for i in range(%d, %d)]' % (offset, offset + length), setup, number=repeats) 
     print '%5d\t%5d\t%10.3f\t%10.3f' % (offset, length, t1 * 100000, t2 * 100000) 
+0

और निश्चित रूप से इसे एक ओवरराइड '__getitem__' विधि में भी लपेटा जा सकता है। – aaronasterling

+0

यह वास्तव में आश्चर्यजनक परिणाम है। – kindall

+4

यह उत्तर * वास्तव में * भ्रामक है और समय से गलत निष्कर्ष निकालता है। डी [i] का उपयोग करके इंडेक्सिंग आमतौर पर तेज़ होता है क्योंकि लुकअप समय पर 62 तत्वों को डेक करता है और क्योंकि यह 'i> len (d) // 2'' के दाहिने ओर जाने के लिए पर्याप्त स्मार्ट है। हालांकि, जब आपको एक लंबे टुकड़े की आवश्यकता होती है, तो एक-बार-समय पर अनुक्रमण करना एक बुरा विचार है। उदाहरण के लिए, यदि आप 30000 तत्वों के डेक में स्लाइस '' 9000: 10000'' के लिए इस समय की कोशिश करते हैं तो आपको एक बहुत अलग जवाब मिलेगा। –