Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/317.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/email/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python:创建子列表而不复制_Python - Fatal编程技术网

Python:创建子列表而不复制

Python:创建子列表而不复制,python,Python,我有一个问题,关于如何从给定列表创建子列表(我希望这是正确使用的术语),而无需复制 似乎切片可以创建子列表,但复制却可以。这里有一个例子 In [1]: a = [1,2,3] In [2]: id(a) Out[2]: 4354651128 In [3]: b = a[0:2] In [4]: b Out[4]: [1, 2] In [5]: id(b) Out[5]: 4354621312 In [6]: id(a[0:2]) Out[6]: 4354620880 参见此处,b和

我有一个问题,关于如何从给定列表创建子列表(我希望这是正确使用的术语),而无需复制

似乎切片可以创建子列表,但复制却可以。这里有一个例子

In [1]: a = [1,2,3]

In [2]: id(a)
Out[2]: 4354651128

In [3]: b = a[0:2]

In [4]: b
Out[4]: [1, 2]

In [5]: id(b)
Out[5]: 4354621312

In [6]: id(a[0:2])
Out[6]: 4354620880
参见此处,b和a[0:2]的id不同,尽管它们的值相同。要进行双重检查,请更改a中的值,b中的值不会更改

In [7]: a[1] = 4

In [8]: a
Out[8]: [1, 4, 3]

In [9]: b
Out[9]: [1, 2]
回到我的问题上来,我如何创建子列表而不复制?我的意思是,当a[1]的值设置为4时,b将是[1,4]

我四处搜索,没有找到太多帮助(也许我没有使用正确的关键字)。谢谢大家!


编辑:

谢谢大家的评论和回答!这是我学到的

  • Python中没有内置的方法来创建列表视图(或者创建子列表而不进行复制)
  • 最简单的方法是使用numpy数组
  • 尽管与列表相比,numpy数组在数据类型上有一些限制,但它确实符合我的目的(实现快速排序而无需额外内存)
以下是numpy数组的相同过程

In [1]: import numpy as np

In [2]: a = np.arange(1,4)

In [3]: a
Out[3]: array([1, 2, 3])

In [4]: b = a[0:2]

In [5]: b
Out[5]: array([1, 2])

In [6]: id(b)
Out[6]: 4361253952

In [7]: id(a[0:2])
Out[7]: 4361254032

In [8]: a[1] = 4

In [9]: a
Out[9]: array([1, 4, 3])

In [10]: b
Out[10]: array([1, 4])

如果你切a得到b,你就不能

所有切片操作都返回一个新列表,其中包含请求的 元素。这意味着下面的切片返回一个新的(浅层) 名单副本[1]


[1] 没有内置的方法来实现这一点。您可以创建自己的类似列表的类,该类引用列表并重新实现所有列表访问器方法以对其进行操作。

内置Python数据结构无法做到这一点。但是,我创建了一个可以满足您需要的类。我不能保证它没有bug,但它应该让你开始

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)
例如:

>>> 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]

numpy
的数组对象支持创建相互依赖的子列表的概念,通过切片返回
视图而不是数据的副本

更改原始
numpy
数组将更改从该数组创建的视图,对任何视图的更改也将反映在原始数组中。特别是对于大型数据集,视图是一种以不同方式剪切数据的好方法,同时可以节省内存

>>> 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

有关进一步的参考,请参见以及。

这种共享的问题是内存泄漏:假设您使用对列表的引用以及值a和b表示一个切片列表[a:b]。然后,即使切片非常小,它也会防止对列表进行垃圾收集,这可能会非常昂贵。当然,您可以使用上述表示为“符号”列表切片定义自定义类。为什么要这样做?我认为您所描述的与
numpy
数组上的视图概念非常接近。有关此主题的一些讨论,请参阅。请注意,与典型的Python列表相比,
numpy
数组在可包含的数据类型方面不够灵活,因此它们可能不适合您的用例,具体取决于您希望包含的数据。@zehnpaard:我非常喜欢您的回答。与“子列表”相比,“视图”更准确地描述了我想要的内容。我尝试过numpy数组,但使用numpy数组进行切片不会产生副本。@PadraicCunningham:我学习了快速排序,并试图实现它,特别是它的无额外内存功能。选择pivot和partitioning之后,我需要分别对左侧和右侧(以及内存中)进行排序。因此,当使用递归时,我希望传递一个视图(或子列表),而不复制。这是一个很好的实现,但有两个方法仍然复制列表,这是不可取的(如len和iter)。感谢您在edit@Dunes中的修复,结果证明它确实像我提到的那样存在错误。我只是想给这家伙一个可以合作的开始。我不会说我所做的更改是错误修复。代码在功能上是正确的。这不仅仅是为了提高课堂的效率,这是为了最大限度地减少对列表的复制。我想我是在重新发明轮子,答案不错。