【问题标题】:How to initialize a two-dimensional array in Python?如何在 Python 中初始化一个二维数组?
【发布时间】:2011-01-24 17:23:47
【问题描述】:

我正在开始使用 python,我正在尝试使用一个二维列表,我最初在每个地方都用相同的变量填充。我想出了这个:

def initialize_twodlist(foo):
    twod_list = []
    new = []
    for i in range (0, 10):
        for j in range (0, 10):
            new.append(foo)
        twod_list.append(new)
        new = []

它给出了预期的结果,但感觉像是一种解决方法。有没有更简单/更短/更优雅的方法来做到这一点?

【问题讨论】:

标签: python multidimensional-array


【解决方案1】:

Python 中经常出现的一种模式是

bar = []
for item in some_iterable:
    bar.append(SOME EXPRESSION)

这有助于促进引入列表推导,将 sn-p 转换为

bar = [SOME_EXPRESSION for item in some_iterable]

它更短,有时更清晰。通常,您会养成识别这些内容并经常用推导式替换循环的习惯。

您的代码两次遵循此模式

twod_list = []                                       \                      
for i in range (0, 10):                               \
    new = []                  \ can be replaced        } this too
    for j in range (0, 10):    } with a list          /
        new.append(foo)       / comprehension        /
    twod_list.append(new)                           /

【讨论】:

  • 顺便说一句,[[foo]*10 for x in xrange(10)] 可以用来摆脱一种理解。问题是乘法是浅拷贝,所以 new = [foo] * 10 new = [new] * 10 会得到一个包含相同列表十次的列表。
  • 类似地,[foo] * 10 是一个列表,有 10 次完全相同的 foo,这可能很重要,也可能不重要。
  • 我们可以使用最简单的方法:wtod_list = [[0 for x in xrange(10))] for x in xrange(10)]
  • @Scott Wolchok 和 Mike Graham - 非常重要的一点是要使与列表的乘法复制对同一列表的引用。如何在没有附加的情况下实例化 MxN 矩阵?
  • 对于 Mike Graham 对 [foo] * 10 的评论:这意味着如果你用随机数填充数组,这将不起作用(评估 [random.randint(1,2)] * 10[1] * 10[2] * 10 这意味着你得到一个全为 1 或 2 的数组,而不是随机数组。
【解决方案2】:

不要使用[[v]*n]*n,这是个陷阱!

>>> a = [[0]*3]*3
>>> a
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
>>> a[0][0]=1
>>> a
[[1, 0, 0], [1, 0, 0], [1, 0, 0]]

但是

    t = [ [0]*3 for i in range(3)]

效果很好。

【讨论】:

  • 是的,我也掉进了这个陷阱。这是因为* 正在复制对象(列表)的address
  • 赞成,因为这吸引了我。为了更清楚,[[0] * col for _ in range(row)].
  • 为什么它适用于第一个维度而不适用于第二个维度? l = [0] * 3 后跟 l[0] = 1 产生 [1, 0, 0] 就好了。
  • 找到了为什么第一个维度有效但第二个维度无效的答案。列表乘法生成浅拷贝。当您分配给索引时,它会进行适当的更改,但访问不会,因此当您执行a[x][y] = 2 时,它正在访问而不是分配第 x 个索引 - 实际上仅更改了第 y 个访问。此页面帮助我解释了可能比我在此评论中尝试解释的图表更好的图表:geeksforgeeks.org/python-using-2d-arrays-lists-the-right-way
  • 这在当前版本的python中可以正常工作。
【解决方案3】:

您可以使用list comprehension

x = [[foo for i in range(10)] for j in range(10)]
# x is now a 10x10 array of 'foo' (which can depend on i and j if you want)

【讨论】:

  • 因为大小(10)是一样的,如果不是嵌套循环必须首先出现 [foo for j in range(range_of_j)] for i in range(range_of_i)]
  • 这个答案很好,但我因为我们迭代 i 为行和 j 为列,我认为最好在你的语法中交换 ij 以便更好地理解并将范围更改为 2 个不同的数字。
【解决方案4】:

这种方式比嵌套列表推导式更快

[x[:] for x in [[foo] * 10] * 10]    # for immutable foo!

这里有一些 python3 时序,适用于小型和大型列表

$python3 -m timeit '[x[:] for x in [[1] * 10] * 10]'
1000000 loops, best of 3: 1.55 usec per loop

$ python3 -m timeit '[[1 for i in range(10)] for j in range(10)]'
100000 loops, best of 3: 6.44 usec per loop

$ python3 -m timeit '[x[:] for x in [[1] * 1000] * 1000]'
100 loops, best of 3: 5.5 msec per loop

$ python3 -m timeit '[[1 for i in range(1000)] for j in range(1000)]'
10 loops, best of 3: 27 msec per loop

解释:

[[foo]*10]*10 创建一个重复 10 次的相同对象的列表。您不能只使用它,因为修改一个元素将修改每一行中的相同元素!

x[:] 等价于list(X),但效率更高一些,因为它避免了名称查找。无论哪种方式,它都会为每一行创建一个浅表副本,因此现在所有元素都是独立的。

虽然所有元素都是相同的 foo 对象,所以如果 foo 是可变的,你不能使用这个方案。你必须使用

import copy
[[copy.deepcopy(foo) for x in range(10)] for y in range(10)]

或假设一个类(或函数)Foo 返回foos

[[Foo() for x in range(10)] for y in range(10)]

【讨论】:

  • @Mike,你错过了粗体部分吗?如果 foo 是可变的,那么这里的其他答案都不起作用(除非你根本没有改变 foo)
  • 您无法使用copy.deepcopy 正确复制任意对象。如果你有一个任意的可变对象,你需要一个特定于你的数据的计划。
  • 如果您在循环中非常需要速度,可能是时候使用 Cython、weave 或类似的...
  • @JohnLaRooy 我认为你互换了xy。不应该是[[copy.deepcopy(foo) for y in range(10)] for x in range(10)]
  • @Nils [foo]*10 不会创建 10 个不同的对象 - 但很容易忽略 foo 不可变情况下的差异,例如 intstr
【解决方案5】:

在 Python 中初始化一个二维数组:

a = [[0 for x in range(columns)] for y in range(rows)]

【讨论】:

  • 要将所有值初始化为0,只需使用a = [[0 for x in range(columns)] for y in range(rows)]
【解决方案6】:
[[foo for x in xrange(10)] for y in xrange(10)]

【讨论】:

  • xrange() 已在 python3.5 中删除
  • 为什么这不起作用:[0 * col] * row.当我修改某些元素时,它会在其他地方复制。但我不明白为什么?
  • 因为它与问题中的代码完全相同。
  • @codemuncher [[0] * col] * row 没有做你想做的事情的原因是当你用这种方式初始化一个二维列表时,Python 不会为每一行创建不同的副本。相反,它将使用指向[0]*col 的同一副本的指针来初始化外部列表。您对其中一行所做的任何编辑都将反映在其余行中,因为它们实际上都指向内存中的相同数据。
  • 只是一个想法,但不是所有这些列表都不适合附加吗? IE。如果我想要一个维度为 3 * 6 的空 2D 列表,并且想要附加到 index[0][0]、[1][0]、[2][0] 等以填充所有 18 个元素,则没有这些答案行得通吗?
【解决方案7】:

通常当您想要多维数组时,您不需要列表列表,而是需要一个 numpy 数组或可能是一个字典。

例如,使用 numpy 你会做类似的事情

import numpy
a = numpy.empty((10, 10))
a.fill(foo)

【讨论】:

  • 虽然numpy 很棒,但我认为对于初学者来说可能有点矫枉过正。
  • numpy 提供了多维数组类型。从列表中构建一个好的多维数组是可能的,但对于初学者来说,它比使用 numpy 更有用且更难。嵌套列表非常适合某些应用程序,但通常不是那些想要二维数组的人最好的选择。
  • 在偶尔做一些严肃的 python 应用程序几年之后,标准 python 数组的怪癖似乎需要继续使用numpy。 +1
【解决方案8】:

你可以这样做:

[[element] * numcols] * numrows

例如:

>>> [['a'] *3] * 2
[['a', 'a', 'a'], ['a', 'a', 'a']]

但这有一个不受欢迎的副作用:

>>> b = [['a']*3]*3
>>> b
[['a', 'a', 'a'], ['a', 'a', 'a'], ['a', 'a', 'a']]
>>> b[1][1]
'a'
>>> b[1][1] = 'b'
>>> b
[['a', 'b', 'a'], ['a', 'b', 'a'], ['a', 'b', 'a']]

【讨论】:

  • 根据我的经验,这种“不受欢迎的”效果通常是一些非常糟糕的逻辑错误的根源。在我看来,应该避免这种方法,而不是@Vipul的答案要好得多。
  • 这种方法效果很好,为什么在 cmets 中有些人认为它很糟糕?
  • 由于副作用不足,您不能真正将其视为矩阵。如果你不需要更改内容,那就可以了。
【解决方案9】:
twod_list = [[foo for _ in range(m)] for _ in range(n)]

因为n是行数,m是列数,foo是值。

【讨论】:

    【解决方案10】:

    如果它是一个稀疏的数组,你最好使用一个以元组为键的字典:

    dict = {}
    key = (a,b)
    dict[key] = value
    ...
    

    【讨论】:

      【解决方案11】:
      t = [ [0]*10 for i in [0]*10]
      

      将为每个元素创建一个新的[0]*10 ..

      【讨论】:

        【解决方案12】:

        代码:

        num_rows, num_cols = 4, 2
        initial_val = 0
        matrix = [[initial_val] * num_cols for _ in range(num_rows)]
        print(matrix) 
        # [[0, 0], [0, 0], [0, 0], [0, 0]]
        

        initial_val 必须是不可变的。

        【讨论】:

          【解决方案13】:

          对于那些对为什么[['']*m]*n 不好用感到困惑的人。
          Python 使用引用调用,因此在上述情况下更改一个值也会导致其他索引值的更改。

          最好的方法是[['' for i in range(m)] for j in range(n)]
          这将解决所有问题。

          更多说明
          示例:

          >>> x = [['']*3]*3
          [['', '', ''], ['', '', ''], ['', '', '']]
          >>> x[0][0] = 1
          >>> print(x)
          [[1, '', ''], [1, '', ''], [1, '', '']]
          
          >>> y = [['' for i in range(3)] for j in range(3)]
          [['', '', ''], ['', '', ''], ['', '', '']]
          >>> y[0][0]=1
          >>> print(y)
          [[1, '', ''], ['', '', ''], ['', '', '']]
          

          【讨论】:

            【解决方案14】:

            不正确的方法:[[None*m]*n]

            >>> m, n = map(int, raw_input().split())
            5 5
            >>> x[0][0] = 34
            >>> x
            [[34, None, None, None, None], [34, None, None, None, None], [34, None, None, None, None], [34, None, None, None, None], [34, None, None, None, None]]
            >>> id(x[0][0])
            140416461589776
            >>> id(x[3][0])
            140416461589776
            

            使用这种方法,python 不允许为外部列创建不同的地址空间,并且会导致各种错误行为超出您的预期。

            正确的方法,但有例外:

            y = [[0 for i in range(m)] for j in range(n)]
            >>> id(y[0][0]) == id(y[1][0])
            False
            

            这是一个很好的方法,但如果将默认值设置为None,则会出现异常

            >>> r = [[None for i in range(5)] for j in range(5)]
            >>> r
            [[None, None, None, None, None], [None, None, None, None, None], [None, None, None, None, None], [None, None, None, None, None], [None, None, None, None, None]]
            >>> id(r[0][0]) == id(r[2][0])
            True
            

            因此,请使用此方法正确设置默认值。

            绝对正确:

            关注double loop的mike回复。

            【讨论】:

              【解决方案15】:

              要初始化二维数组,请使用: arr = [[]*m for i in range(n)]

              其实, arr = [[]*m]*n 将创建一个二维数组,其中所有 n 个数组将指向同一个数组,因此任何元素中值的任何变化都将反映在所有 n 个列表中

              更多解释请访问:https://www.geeksforgeeks.org/python-using-2d-arrays-lists-the-right-way/

              【讨论】:

                【解决方案16】:

                使用最简单的想法来创建它。

                wtod_list = []
                

                并添加尺寸:

                wtod_list = [[0 for x in xrange(10)] for x in xrange(10)]
                

                或者如果我们想先声明尺寸。我们只使用:

                   wtod_list = [[0 for x in xrange(10)] for x in xrange(10)]
                

                【讨论】:

                  【解决方案17】:

                  用 0 初始化一个大小为 m X n 的二维矩阵

                  m,n = map(int,input().split())
                  l = [[0 for i in range(m)] for j in range(n)]
                  print(l)
                  

                  【讨论】:

                  • 你能告诉我,当我们执行 [[0]*m]*n 时,它会创建类似的二维列表,但不像矩阵那样索引?
                  • @Rehan 是的,这绝对是 python 的垃圾行为。我只是困惑了几十分钟
                  【解决方案18】:
                  Matrix={}
                  for i in range(0,3):
                    for j in range(0,3):
                      Matrix[i,j] = raw_input("Enter the matrix:")
                  

                  【讨论】:

                  • 虽然此代码可能会回答问题,但提供有关此代码为何和/或如何回答问题的额外上下文可提高其长期价值。
                  【解决方案19】:

                  如果你使用numpy,你可以轻松创建二维数组:

                  import numpy as np
                  
                  row = 3
                  col = 5
                  num = 10
                  x = np.full((row, col), num)
                  

                  x

                  array([[10, 10, 10, 10, 10],
                         [10, 10, 10, 10, 10],
                         [10, 10, 10, 10, 10]])
                  

                  【讨论】:

                  • 鉴于 python 的 [[0]*M]*N糟糕 行为创建了 @JasonChan 描述的“陷阱” - 是的,让我们使用 numpy (这确实是主要原因无论如何都要使用python)
                  【解决方案20】:
                  row=5
                  col=5
                  [[x]*col for x in [b for b in range(row)]]
                  

                  上面会给你一个 5x5 2D 数组

                  [[0, 0, 0, 0, 0],
                   [1, 1, 1, 1, 1],
                   [2, 2, 2, 2, 2],
                   [3, 3, 3, 3, 3],
                   [4, 4, 4, 4, 4]]
                  

                  它使用嵌套列表推导。 细分如下:

                  [[x]*col for x in [b for b in range(row)]]
                  

                  [x]*col --> 被评估的最终表达式
                  for x in --> x 将是迭代器提供的值
                  [b for b in range(row)]] --> 迭代器。

                  [b for b in range(row)]] 这将评估为 [0,1,2,3,4],因为 row=5
                  所以现在它简化为

                  [[x]*col for x in [0,1,2,3,4]]
                  

                  这将评估为 [[0]*5 for x in [0,1,2,3,4]] --> x=0 第一次迭代
                  [[1]*5 for x in [0,1,2,3,4]] --> x=1 第二次迭代
                  [[2]*5 for x in [0,1,2,3,4]] --> x=2 第三次迭代
                  [[3]*5 for x in [0,1,2,3,4]] --> x=3 第 4 次迭代
                  [[4]*5 for x in [0,1,2,3,4]] --> x=4 第 5 次迭代

                  【讨论】:

                    【解决方案21】:

                    正如@Arnab 和@Mike 所指出的,数组不是列表。几个区别是 1) 数组在初始化期间是固定大小的 2) 数组通常支持比列表更少的操作。

                    在大多数情况下可能有点矫枉过正,但这里是一个基本的二维数组实现,它利用使用 python ctypes(c 库)的硬件数组实现

                    import ctypes
                    class Array:
                        def __init__(self,size,foo): #foo is the initial value
                            self._size = size
                            ArrayType = ctypes.py_object * size
                            self._array = ArrayType()
                            for i in range(size):
                                self._array[i] = foo
                        def __getitem__(self,index):
                            return self._array[index]
                        def __setitem__(self,index,value):
                            self._array[index] = value
                        def __len__(self):
                            return self._size
                    
                    class TwoDArray:
                        def __init__(self,columns,rows,foo):
                            self._2dArray = Array(rows,foo)
                            for i in range(rows):
                                self._2dArray[i] = Array(columns,foo)
                    
                        def numRows(self):
                            return len(self._2dArray)
                        def numCols(self):
                            return len((self._2dArray)[0])
                        def __getitem__(self,indexTuple):
                            row = indexTuple[0]
                            col = indexTuple[1]
                            assert row >= 0 and row < self.numRows() \
                                   and col >=0 and col < self.numCols(),\
                                   "Array script out of range"
                            return ((self._2dArray)[row])[col]
                    
                    if(__name__ == "__main__"):
                        twodArray = TwoDArray(4,5,5)#sample input
                        print(twodArray[2,3])
                    

                    【讨论】:

                      【解决方案22】:

                      这是我发现的最好的用于教授新程序员的方法,而且无需使用额外的库。不过我想要更好的东西。

                      def initialize_twodlist(value):
                          list=[]
                          for row in range(10):
                              list.append([value]*10)
                          return list
                      

                      【讨论】:

                        【解决方案23】:

                        这是一个更简单的方法:

                        import numpy as np
                        twoD = np.array([[]*m]*n)
                        

                        使用任何“x”值初始化所有单元格:

                        twoD = np.array([[x]*m]*n
                        

                        【讨论】:

                          【解决方案24】:

                          我经常使用这种方法来初始化一个二维数组

                          n=[[int(x) for x in input().split()] for i in range(int(input())]

                          【讨论】:

                            【解决方案25】:

                            添加维度的一般模式可以从这个系列中得出:

                            x = 0
                            mat1 = []
                            for i in range(3):
                                mat1.append(x)
                                x+=1
                            print(mat1)
                            
                            
                            x=0
                            mat2 = []
                            for i in range(3):
                                tmp = []
                                for j in range(4):
                                    tmp.append(x)
                                    x+=1
                                mat2.append(tmp)
                            
                            print(mat2)
                            
                            
                            x=0
                            mat3 = []
                            for i in range(3):
                                tmp = []
                                for j in range(4):
                                    tmp2 = []
                                    for k in range(5):
                                        tmp2.append(x)
                                        x+=1
                                    tmp.append(tmp2)
                                mat3.append(tmp)
                            
                            print(mat3)
                            

                            【讨论】:

                            • 欢迎来到 SO。这个问题已经有一个被大量接受的答案。乍一看,这篇文章实际上并没有回答这个问题。请参阅stackoverflow.com/help/how-to-answer 以获得指导。
                            【解决方案26】:

                            我理解的重要一点是:在初始化一个数组时(在任何维度上)我们应该给数组的所有位置一个默认值。然后只有初始化完成。之后,我们可以将新值更改或接收到数组的任何位置。下面的代码非常适合我

                            N=7
                            F=2
                            
                            #INITIALIZATION of 7 x 2 array with deafult value as 0
                            ar=[[0]*F for x in range(N)]
                            
                            #RECEIVING NEW VALUES TO THE INITIALIZED ARRAY
                            for i in range(N):
                                for j in range(F):
                                    ar[i][j]=int(input())
                            print(ar)
                            
                            

                            【讨论】:

                            • 这仍然是陷阱,如接受的答案中所述
                            【解决方案27】:

                            另一种方法是使用字典来保存二维数组。

                            twoD = {}
                            twoD[0,0] = 0
                            print(twoD[0,0]) # ===> prints 0
                            

                            这只能保存任何一维、二维值,并将其初始化为0 或任何其他 int 值,请使用 collections

                            import collections
                            twoD = collections.defaultdict(int)
                            print(twoD[0,0]) # ==> prints 0
                            twoD[1,1] = 1
                            print(twoD[1,1]) # ==> prints 1
                            

                            【讨论】:

                              【解决方案28】:
                              lst=[[0]*n]*m
                              np.array(lst)
                              

                              初始化所有矩阵 m=rows 和 n=columns

                              【讨论】:

                              • 能否将代码格式化为代码?这将更具可读性。
                              【解决方案29】:

                              我用这种方式创建mxn矩阵,其中m = no(rows)n = no(columns)

                              arr = [[None]*(n) for _ in range(m)]
                              

                              【讨论】:

                                【解决方案30】:
                                from random import randint
                                l = []
                                
                                for i in range(10):
                                    k=[]
                                    for j in range(10):
                                        a= randint(1,100)
                                        k.append(a)
                                
                                    l.append(k)
                                
                                
                                
                                
                                print(l)
                                print(max(l[2]))
                                
                                b = []
                                for i in range(10):
                                    a = l[i][5]
                                    b.append(a)
                                
                                print(min(b))
                                

                                【讨论】:

                                猜你喜欢
                                • 1970-01-01
                                • 2012-04-14
                                • 2021-04-04
                                • 1970-01-01
                                • 2018-03-02
                                • 1970-01-01
                                • 2011-12-08
                                • 1970-01-01
                                • 1970-01-01
                                相关资源
                                最近更新 更多