Python: create sublist without copying

前端 未结 4 937
执笔经年
执笔经年 2021-02-13 16:35

I have a question about how to create a sublist (I hope this is the right term to use) from a given list without copying.

It seems that slicing can create sublists, but

相关标签:
4条回答
  • 2021-02-13 16:49

    numpy's array objects support this notion of creating interdependent sub-lists, by having slicing return views rather than copies of the data.

    Altering the original numpy array will alter the views created from the array, and changes to any of the views will also be reflected in the original array. Especially for large data sets, views are a great way of cutting data in different ways, while saving on memory.

    >>> import numpy as np
    >>> array1 = np.array([1, 2, 3, 4])
    >>> view1 = array1[1:]
    >>> view1
    array([2, 3, 4])
    >>> view1[1] = 5
    >>> view1
    array([2, 5, 4])
    >>> array1
    array([1, 2, 5, 4]) # Notice that the change to view1 has been reflected in array1
    

    For further reference, see the numpy documentation on views as well as this SO post.

    0 讨论(0)
  • 2021-02-13 16:54

    There is no way to do this with built in Python data structures. However, I created a class that does what you need. I don't guarantee it to be bug-free, but it should get you started.

    from itertools import islice
    
    class SubLister(object):
        def __init__(self, base=[], start=0, end=None):
            self._base = base
            self._start = start
            self._end = end
    
        def __len__(self):
            if self._end is None:
                return len(self._base) - self._start
            return self._end - self._start
    
        def __getitem__(self, index):
            self._check_end_range(index)
            return self._base[index + self._start]
    
        def __setitem__(self, index, value):
            self._check_end_range(index, "list assignment index out of range")
            self._base[index + self._start] = value
    
        def __delitem__(self, index):
            self._check_end_range(index, "list assignment index out of range")
            del self._base[index + self._start]
    
        def __iter__(self):
            return islice(self._base, self._start, self._end)
    
        def __str__(self):
            return str(self._base[self._start:self._end])
    
        def __repr__(self):
            return repr(self._base[self._start:self._end])
    
        # ...etc...
    
        def get_sublist(self, start=0, end=None):
            return SubLister(base=self._base, start=start, end=end)
    
        def _check_end_range(self, index, msg="list index out of range"):
            if self._end is not None and index >= self._end - self._start:
                raise IndexError(msg)
    

    Example:

    >>> from sublister import SubLister
    >>> base = SubLister([1, 2, 3, 4, 5])
    >>> a = base.get_sublist(0, 2)
    >>> b = base.get_sublist(1)
    
    >>> base
    [1, 2, 3, 4, 5]
    >>> a
    [1, 2]
    >>> b
    [2, 3, 4, 5]
    >>> len(base)
    5
    >>> len(a)
    2
    >>> len(b)
    4
    
    >>> base[1] = 'ref'
    >>> base
    [1, 'ref', 3, 4, 5]
    >>> a
    [1, 'ref']
    >>> b
    ['ref', 3, 4, 5]
    
    0 讨论(0)
  • 2021-02-13 17:05

    There is no built-in way to do this. You could create your own list-like class that takes a reference to a list and reimplements all of the list accessor methods to operate on it.

    0 讨论(0)
  • you can't if you slice a to get b.

    All slice operations return a new list containing the requested elements. This means that the following slice returns a new (shallow) copy of the list [1]

    [1] https://docs.python.org/2/tutorial/introduction.html

    0 讨论(0)
提交回复
热议问题