2010-08-14 14 views
34

मेरे पास एक बड़ी सूची l है। मैं तत्व 4 से 6 तक एक दृश्य बनाना चाहता हूं। मैं इसे अनुक्रम स्लाइस के साथ कर सकता हूं।क्या मैं पाइथन सूची पर "दृश्य" बना सकता हूं?

>>> l=range(10) 
>>> lv=l[3:6] 
>>> lv 
[3, 4, 5] 

हालांकि एलवी एल के टुकड़े की प्रति है। अगर मैं अंतर्निहित सूची बदलता हूं, तो एलवी परिवर्तन को प्रतिबिंबित नहीं करता है।

>>> l[4] = -1 
>>> lv 
[3, 4, 5] 

इसके विपरीत मैं एल में भी प्रतिबिंबित करने पर संशोधन चाहता हूं। इसके अलावा सूची का आकार बदला नहीं जा रहा है।

मैं ऐसा करने के लिए एक बड़ी कक्षा बनाने की उम्मीद नहीं कर रहा हूं। मैं बस उम्मीद कर रहा हूं कि अन्य पायथन गुरु कुछ छिपी हुई भाषा चाल जान सकते हैं। आदर्श रूप में मुझे आशा है कि यह सी

में
int lv[] = l + 3; 
+0

किसी भी व्यक्ति के लिए जो इस प्रश्न में आया है, [स्मृतिदृश्य] (https://docs.python.org/2/library/stdtypes.html#memoryview) अब यह क्षमता प्रदान करता है। – robert

+0

@robert कैसे? 'मेमोरीव्यू' केवल बफर इंटरफेस वाली वस्तुओं के लिए काम करता है और सूची उनमें से एक नहीं है। – zegkljan

+0

यहां प्रदान किए गए उदाहरण में आपको सूची के बजाय 'bytearray' का उपयोग करना चाहिए। आप सूची को 'bytearray' में भी लपेट सकते हैं। – robert

उत्तर

28

पायथन मानक पुस्तकालय में कोई "सूची टुकड़ा" वर्ग नहीं है (न ही एक अंतर्निहित है)। इसलिए, आपको कक्षा की आवश्यकता है, हालांकि इसे बड़ा नहीं होना चाहिए - खासकर यदि आप "केवल पढ़ने योग्य" और "कॉम्पैक्ट" टुकड़े से संतुष्ट हैं। उदा .:

import collections 

class ROListSlice(collections.Sequence): 

    def __init__(self, alist, start, alen): 
     self.alist = alist 
     self.start = start 
     self.alen = alen 

    def __len__(self): 
     return self.alen 

    def adj(self, i): 
     if i<0: i += self.alen 
     return i + self.start 

    def __getitem__(self, i): 
     return self.alist[self.adj(i)] 

यह कुछ सीमाएं (समर्थन नहीं करता है "एक टुकड़ा टुकड़ा करने की क्रिया") लेकिन सबसे प्रयोजनों के लिए ठीक हो सकता है है।

बनाने के इस क्रम आर/डब्ल्यू आप __setitem__, __delitem__, और insert जोड़ने की जरूरत:

class ListSlice(ROListSlice): 

    def __setitem__(self, i, v): 
     self.alist[self.adj(i)] = v 

    def __delitem__(self, i, v): 
     del self.alist[self.adj(i)] 
     self.alen -= 1 

    def insert(self, i, v): 
     self.alist.insert(self.adj(i), v) 
     self.alen += 1 
+2

'__length__'' __len__' होना चाहिए, नहीं? – intuited

+0

क्या आप 'def __slice __ (self, * args, ** kwargs) जैसे कुछ कर सकते हैं: वापसी (self.alist [self.start: self.start + self.alen]) .__ टुकड़ा __ (* args, ** kwargs)' टुकड़ा करने जैसी चीजों का समर्थन करने के लिए? मूल रूप से ऑन-डिमांड पर बनाए गए टुकड़े के अनुरोध के माध्यम से गुज़रना। – Amber

+3

लेकिन यदि आप 'alist.insert (0, कुछ) करते हैं तो टुकड़ा चलता है! यह समस्या हो सकती है या नहीं भी हो सकता है ... –

5

सूचक अंकगणित की तरह कर सकते हैं आप क्या कर सकते हैं कि मूल सूची संदर्भ का उपयोग कर अपने स्वयं के जनरेटर बनाने के द्वारा।

l = [1,2,3,4,5] 
lv = (l[i] for i in range(1,4)) 

lv.next() # 2 
l[2]=-1 
lv.next() # -1 
lv.next() # 4 

हालांकि यह एक जनरेटर जा रहा है, आप केवल एक बार सूची के माध्यम से जा सकते हैं, आगे और यदि आप और अधिक तत्वों की तुलना में आप range साथ अनुरोध किया हटाने यह विस्फोट हो जाएगा।

0

आप कर सकते थे संपादित करें: जैसे

shiftedlist = type('ShiftedList', 
        (list,), 
        {"__getitem__": lambda self, i: list.__getitem__(self, i + 3)} 
       )([1, 2, 3, 4, 5, 6]) 

अनिवार्य रूप से होने के नाते कुछ करना नहीं एक लाइनर, यह बहुत पाइथनिक नहीं है, लेकिन यह मूलभूत बात है।

संपादित करें: मैं देर से ही सही महसूस किया है कि इस वजह से list() सूची इसे पारित है की एक उथले नकल करना अनिवार्य होगा काम नहीं करता। इसलिए यह सूची को टुकड़ा करने के समान ही कम हो जाएगा। दरअसल कम, __len__ के लापता ओवरराइड के कारण। आपको प्रॉक्सी क्लास का उपयोग करना होगा; विवरण के लिए Mr. Martelli's answer देखें।

27

शायद सिर्फ एक numpy सरणी का उपयोग करें:

In [19]: import numpy as np 

In [20]: l=np.arange(10) 

बुनियादी टुकड़ा करने की क्रिया को NumPy सरणी returns a view, नहीं एक प्रतिलिपि:

In [21]: lv=l[3:6] 

In [22]: lv 
Out[22]: array([3, 4, 5]) 

फेरबदल l को प्रभावित करता है lv:

In [23]: l[4]=-1 

In [24]: lv 
Out[24]: array([ 3, -1, 5]) 

और lv फेरबदल को प्रभावित करता है l:

In [25]: lv[1]=4 

In [26]: l 
Out[26]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) 
1

संपादित करें:The object argument must be an object that supports the buffer call interface (such as strings, arrays, and buffers). - तो नहीं, दुर्भाग्य से।

मुझे लगता है कि buffer type वह है जिसे आप ढूंढ रहे हैं। लिंक किए गए पृष्ठ से

चिपकाने उदाहरण:

>>> s = bytearray(1000000) # a million zeroed bytes 
>>> t = buffer(s, 1)   # slice cuts off the first byte 
>>> s[1] = 5     # set the second element in s 
>>> t[0]      # which is now also the first element in t! 
'\x05' 
+0

पायथन 3 में कोई 'बफर() 'बिल्टिन नहीं है।' स्मृतिदृश्य()' का उपयोग इसके बजाय किया जा सकता है। – jfs

+0

इसके अलावा, यह क्षेत्र के मेमोरी बाइट्स में निरीक्षण करता है - पायथन सूची में ऑब्जेक्ट्स (जो 'स्मृति में' ऑब्जेक्ट्स के लिए पॉइंटर होते हैं) होते हैं - निश्चित रूप से, यह एक बहुत ही गलत दृष्टिकोण होगा - किसी को 'ctypes' का उपयोग करना होगा , और सभी पॉइंटर संकेतक कार्य को फिर से करें, जैसे कि वह सी में कोडिंग कर रहा था, कि पायथन मुफ्त – jsbueno

1

जैसे ही आप एक सूची से एक टुकड़ा ले जाएगा, तो आप एक नई सूची बनाने की जाएगी। ठीक है, इसमें वही ऑब्जेक्ट्स होंगे जब तक कि सूची की ऑब्जेक्ट्स संबंधित हों, लेकिन यदि आप स्लाइस को संशोधित करते हैं तो मूल सूची अपरिवर्तित होती है।

तुम सच में एक परिवर्तनीय दृश्य बनाना चाहते हैं, तो आप एक नया collection.MutableSequence

के आधार पर वर्ग कल्पना कर सकता यह एक पूर्ण विशेषताओं उप सूची के लिए एक प्रारंभिक बिंदु हो सकता है - यह सही ढंग से टुकड़ा अनुक्रमित प्रोसेस करता है, लेकिन कम से कम है नकारात्मक अनुक्रमित प्रसंस्करण के लिए कमी विनिर्देश:

class Sublist(collections.MutableSequence): 
    def __init__(self, ls, beg, end): 
     self.ls = ls 
     self.beg = beg 
     self.end = end 
    def __getitem__(self, i): 
     self._valid(i) 
     return self.ls[self._newindex(i)] 
    def __delitem__(self, i): 
     self._valid(i) 
     del self.ls[self._newindex(i)] 
    def insert(self, i, x): 
     self._valid(i) 
     self.ls.insert(i+ self.beg, x) 
    def __len__(self): 
     return self.end - self.beg 
    def __setitem__(self, i, x): 
     self.ls[self._newindex(i)] = x 
    def _valid(self, i): 
     if isinstance(i, slice): 
      self._valid(i.start) 
      self._valid(i.stop) 
     elif isinstance(i, int): 
      if i<0 or i>=self.__len__(): 
       raise IndexError() 
     else: 
      raise TypeError() 
    def _newindex(self, i): 
     if isinstance(i, slice): 
      return slice(self.beg + i.start, self.beg + i.stop, i.step) 
     else: 
      return i + self.beg 

उदाहरण:

>>> a = list(range(10)) 
>>> s = Sublist(a, 3, 8) 
>>> s[2:4] 
[5, 6] 
>>> s[2] = 15 
>>> a 
[0, 1, 2, 3, 4, 15, 6, 7, 8, 9] 
+0

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

0

आप वें पहुँचने के होने जा रहे हैं, तो अनुक्रमिक रूप से ई "देखें" तो आप itertools.islice (..) You can see the documentation for more info का उपयोग कर सकते हैं।

l = [1, 2, 3, 4, 5] 
d = [1:3] #[2, 3] 
d = itertools.islice(2, 3) # iterator yielding -> 2, 3 

आप उन्हें टुकड़ा में परिवर्तित करने के लिए अलग-अलग तत्वों का उपयोग नहीं कर सकते हैं और यदि आप इस सूची में परिवर्तन कर आप फिर से कॉल करने के लिए (..) isclice है।

0

अनुक्रमों को उत्परिवर्तित करके और इसके विपरीत दृश्यों को प्रभावित करने के लिए more_itertools.SequenceView उप-वर्ग।

कोड

import more_itertools as mit 


class SequenceView(mit.SequenceView): 
    """Overload assignments in views.""" 
    def __setitem__(self, index, item): 
     self._target[index] = item 

डेमो

>>> seq = list(range(10)) 
>>> view = SequenceView(seq) 
>>> view 
SequenceView([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) 

>>> # Mutate Sequence -> Affect View 
>>> seq[6] = -1 
>>> view[5:8] 
[5, -1, 7] 

>>> # Mutate View -> Affect Sequence 
>>> view[5] = -2 
>>> seq[5:8] 
[-2, -1, 7] 

more_itertools एक तीसरी पार्टी पुस्तकालय है। > pip install more_itertools के माध्यम से स्थापित करें।

संबंधित मुद्दे