2d数组的零

yak*_*xxx 33 python

python中没有数组类型,但为了模拟它我们可以使用列表.我希望用零填充2d数组结构.我的问题是:在这两个表达式中有什么区别,如果有的话:

zeros = [[0 for i in xrange(M)] for j in xrange(M)]
Run Code Online (Sandbox Code Playgroud)

zeros = [[0]*M]*N
Run Code Online (Sandbox Code Playgroud)

zeros一样吗?通过速度和可读性更好地使用哪一个?

mgi*_*son 49

你应该用numpy.zeros.如果这不是一个选项,您需要第一个版本.在第二个版本中,如果您更改一个值,它将在列表中的其他位置更改 - 例如:

>>> a = [[0]*10]*10
>>> a
[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
>>> a[0][0] = 1
>>> a
[[1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
Run Code Online (Sandbox Code Playgroud)

这是因为(当你从里到外读取表达式时),你创建了一个10个零的列表.然后,您创建一个包含10个零初始列表的10个引用的列表.


注意:

zeros = [ [0]*M for _ in xrange(N) ]
Run Code Online (Sandbox Code Playgroud)

也将工作,它避免嵌套列表理解.如果numpy不在桌面上,这是我将使用的形式.

  • @yakxxx - 注意`[[0]*M for _ in xrange(N)]`也可以工作并避免嵌套list-comp(因为0是不可变的) (5认同)
  • @johnthexiii——可能不是。但是,如果 OP 想要一个由 0 组成的二维数组,我愿意冒险说 OP 的代码也可能在其他地方从 numpy 中受益。 (2认同)

Zhe*_* Hu 15

对于Python 3(不再是xrange),首选答案

zeros = [ [0] * N for _ in range(M)]
Run Code Online (Sandbox Code Playgroud)

对于M x N个零的数组

  • 他的版本会创建引用,因此如果您更改了某个值,所有行中的值都会发生更改,如上面的注释中所述。 (2认同)
  • @AnmolJagetia 此列表理解不会创建对同一“[0]*N”列表的“M”引用;它将创建“M”这样的列表,并且您不应该看到一行的突变影响任何其他行。在列表理解中,例如“[expr for _ in range(M)]”,“expr”被评估“M”次,在这种情况下会创建“M”列表。同时,“[expr]*M”将计算“expr”一次,从而创建对“expr”计算结果的“M”引用(“[0]*N”不是问题,因为 0 是一个不可变的基元,它将被复制)。 (2认同)

Iva*_*tyk 11

在第二种情况下,您将创建对同一列表的引用列表.如果您有以下代码:

[lst] * N
Run Code Online (Sandbox Code Playgroud)

如果lst是对列表的引用,您将拥有以下列表:

[lst, lst, lst, lst, ..., lst]
Run Code Online (Sandbox Code Playgroud)

但是因为结果列表包含对同一对象的引用,所以如果更改一行中的值,它将在所有其他行中更改.


Nia*_*wad 5

胡哲的答案是比较安全的,应该是最好的答案。这是因为如果我们使用接受的答案方法

a = [[0] * 2] * 2
a[0][0] = 1
print(a)
Run Code Online (Sandbox Code Playgroud)

会给出答案

[[1,0],[1,0]]
Run Code Online (Sandbox Code Playgroud)

因此,即使您只想更新第一行第一列的值,同一列中的所有值也会更新。然而

a = [[0] * 2 for _ in range(2)]
a[0][0] = 1
print(a)
Run Code Online (Sandbox Code Playgroud)

给出了正确答案

[[1,0],[0,0]]
Run Code Online (Sandbox Code Playgroud)