Python生成列表具有唯一的词法元素

时间:2013-08-21 22:50:01

标签: python arrays list list-comprehension

假设我想制作一个空的3x4 2d数组。

x = [[0.0]*3]*4

但是,使用上面的代码,

print x[0] is x[1]     # Output = True

含义,

x[1][1] = 5.0
print x      # Output = [[0.0, 5.0, 0.0], 
             #           [0.0, 5.0, 0.0], 
             #           [0.0, 5.0, 0.0], 
             #           [0.0, 5.0, 0.0]]

为了绕过创建此列表,其中包含对同一列表的4个相同引用,我一直在做类似的事情:

y = [[0.0]*3, [0.0]*3, [0.0]*3, [0.0]*3]

其中

print y[0] is y[1]     # Output = False
y[1][1] = 5.0
print y      # Output = [[0.0, 0.0, 0.0], 
             #           [0.0, 5.0, 0.0], 
             #           [0.0, 0.0, 0.0], 
             #           [0.0, 0.0, 0.0]]

另一种方法是使用列表理解

z = [[0.0]*3 for x in range(4)]

但是,这似乎仍然有点难看。

有没有办法让数组'y'或'z'所有引用在优雅格式中是唯一的,例如在'x'中使用列表中的乘法?

2 个答案:

答案 0 :(得分:4)

列表理解是通常的答案。不像序列乘法一样干净,但是最好的可用:

[[0.0]*3 for _ in xrange(4)]

请注意,对于您想要一个值网格的许多应用程序,您正在做一些numpy ndarrays可以做得更快更干净的事情。

答案 1 :(得分:3)

这是官方Python编程常见问题解答,How do I create a multidimensional list?

常见问题解答提出了三种可能性:

  1. 创建所需长度的列表,然后替换循环中的每个元素。
  2. 使用列表理解。
  3. 首先使用类似numpy.array的内容而不是多维列表。
  4. 我认为大多数Python开发人员会以与他们在FAQ中列出的完全相反的顺序提出这些建议......但是没有人会抱怨他们中的任何一个。所以:

    a = np.zeros((3, 4))
    
    a = [[0.0]*3 for _ in range(4)]
    
    a = [None] * 4
    for i, _ in enumerate(a):
        a[i] = [0.0]*3
    

    如果你发现自己经常这么做(而不是使用numpy),你总是可以将它包装在一个函数中。事实上,这通常是处理看起来很丑的任何的最佳方式,即使你正在尽可能地进行python。所以:

    def make_matrix(r, c):
        return [[0.0]*c for _ in range(r)]
    

    然后它尽可能清楚:

    a = make_matrix(3, 4)
    

    itertools有一个名为repeat的函数,它等同于*的迭代器版本。文档显示了一些等效的纯Python代码,因此很容易使其适应(浅或深)复制每个代表的对象:

    def repeat(obj, times):
        for _ in range(times):
            yield copy.copy(obj)
    
    list(repeat([0.0]*3, 4))
    

    我认为这不是更具可读性 - 特别是如果你想在多个级别使用它:

    list(repeat(list(repeat(0.0, 3)), 4))
    

    ...即使你将它包装在一个让你感觉良好的函数中:

    def srepeat(object, times):
        return list(repeat(object, times))
    srepeat(srepeat(0.0, 3), 4)
    

    ...如果你将它包装在一个处理多个维度的函数中,你只需重新创建make_matrix