在不创建任何对象副本的情况下展平Python列表?

时间:2012-08-26 19:09:32

标签: python arrays list multidimensional-array flatten

所以我正在用Python编写一个游戏,而我正在尝试解决的问题要求我将2D列表(即列表列表)转换为一维列表。我已经看到了几种方法,但我不知道是否有任何方法可以创建其中包含的任何对象的副本,或者只是新引用。老实说,Python标准库让我感到困惑,因为对象/序列是否被复制或者只是被引用填充并不总是很明显。

这些是关于我的特殊情况的假设;

  • 我们可以假设我的2D列表(如果表示为矩阵)是完全矩形的。
  • 如果我能得到一个上述假设不正确的解决方案,那就太好了,但目前不需要。
  • 无需担心3D +列表。

谢谢!

4 个答案:

答案 0 :(得分:7)

虽然我不能说出你可能看到的每一种方式,但由于Python的对象语义,通常不会有任何副本。

>>> a = [[1,2.3,'3', object()], [None, [2,3], 4j]]
>>> b = [v for row in a for v in row]
>>> a
[[1, 2.3, '3', <object object at 0x1002af090>], [None, [2, 3], 4j]]
>>> b
[1, 2.3, '3', <object object at 0x1002af090>, None, [2, 3], 4j]
>>> [id(obj) for row in a for obj in row]
[4298185464, 4298195480, 4299558664, 4297781392, 4296523616, 4299692656, 4297773296]
>>> [id(obj) for obj in b]
[4298185464, 4298195480, 4299558664, 4297781392, 4296523616, 4299692656, 4297773296]

v并不意味着“某个新对象等于v”,它只是意味着v,即对象本身。

答案 1 :(得分:1)

关于你关于副本/引用的问题,Python以不同的方式使用可变/不可变变量:对于不可变变量(int,float,string,tuples等),你将获得副本,可变(其他所有) - “引用”

关于python列表的扁平化:查看itertools模块。你可以这样做:

>>> from itertools import chain
>>> chain(*[[1,2,3], [4,5,6], [7,8,9]])
<itertools.chain object at 0x104ff5110>
>>> list(_)
[1, 2, 3, 4, 5, 6, 7, 8, 9]

答案 2 :(得分:1)

python documentation中的这篇文章可能会帮助你理解python的作用:

  

没有人“拥有”一个物体;但是,你可以拥有一个引用   宾语。对象的引用计数现在定义为数量   拥有对它的引用。引用的所有者负责   在不再需要引用时调用Py_DECREF()。所有权   参考可以转移。处理有三种方法   拥有的引用:传递,存储或调用Py_DECREF()。   忘记处置自己的引用会造成内存泄漏。

现在,这指的是使用C代码中的python对象,但是,由于解释器正是这样做的,所以你可以理解如何在python中管理对象和引用。

“没有人拥有对象”,因此当您将项目放入列表时,此列表复制该项目,它只拥有引用。实际上,它发生的是复制指针并增加引用计数(也可能减少被替换的其他对象)。

从python的角度来看,您无法访问对象,只能访问对象。 您可以放入变量的任何内容实际上是对对象的引用。 因此[1,2].append(3)不会复制3,而只是复制参考。

如果要复制对象,则应使用copy模块 或者,对于某些类型,使用对象作为参数调用类(例如int(1234)创建“1234”的副本,即使python在小数组中存储从-5到256的整数和小字符串,这样做int(42)不会复制“42”)

答案 3 :(得分:0)

您可以执行以下操作:

arr2d = [[1,2,3],[4,5,6],[7,8,9]]
arr1d = []
for x in arr2d:
   arr1d.extend(x)

这不会创建副本,更改1d数组,它不会反映。对于将来的参考,如果您想确保不复制它,请导入copy模块,并使用copy.deepcopy(array)而不是array,这样您就会安全。