如何在Python中初始化二维数组?


262

我开始使用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 = []

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


7
只是一个很小的(或者很重要,取决于谁在看)nitpick:列表不是数组。如果需要数组,请使用numpy。
Arnab Datta 2012年

这个问题很相似:它讨论了Python中多维数组的初始化。
安德森·格林

@ArnabDatta那么,如何在numpy中初始化多维数组?
安德森格林


您可以在默认的Python中以类似于结构的数组形式排列数据,但它的效率或实用性不如NumPy数组。特别是如果您要处理大型数据集。这是一些文档docs.scipy.org/doc/numpy-1.10.1/user/basics.creation.html
jmdeamer

Answers:


376

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

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

这有助于激励列表理解的引入,从而将代码段转换为

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

35
顺便说一下,可以使用[[foo] * 10 for xrange(10)中的x]摆脱一种理解。问题是乘法会进行浅表复制,因此new = [foo] * 10 new = [new] * 10将为您提供包含相同列表十次的列表。
Scott Wolchok 2010年

8
类似地,[foo] * 10列表具有相同的精确foo10倍,这可能很重要,也可能并不重要。
Mike Graham 2010年

2
我们可以使用最简单的方法:wtod_list = [[xrange(10)中的x为0] [xrange(10)中的x为]]
indi60 2014年

2
向某人展示鱼的样子从来没有什么坏处。
Csteele5'2

2
对于迈克·格雷厄姆的有关评论[foo] * 10:这意味着,这是行不通的,如果你填充随机数(计算一个阵列[random.randint(1,2)] * 10,以[1] * 10[2] * 10这意味着你得到的,而不是一个随机的阵列中的所有1秒或2秒的阵列。
姿丽

224

您可以使用列表推导

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)

1
由于大小(10)相同,所以很好,如果不是嵌套循环,则必须先行[对于range(range_of_i)中j的foo]对于range(range_of_i)中的i]
Dineshkumar

2
这个答案很好用,但是我因为我们要遍历i行和j列,所以我认为交换ij语法更好,以便更好地理解并将范围更改为2个不同的数字。
DragonKnight

138

这种方法比嵌套列表理解要快

[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是mutable,则不能使用此方案。必须使用

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

4
@Mike,您是否错过了粗体部分?如果foo是可变的,那么这里没有其他答案有效(除非您根本不更改foo)
John La Rooy

1
您不能使用正确复制任意对象copy.deepcopy。如果您有任意可变的对象,则需要特定于数据的计划。
Mike Graham

1
如果您急需一个循环中极高的速度,可能是时候使用Cython,编织或类似方法了……
james.haggerty 2012年

1
@JohnLaRooy我想你互换xy。不应该[[copy.deepcopy(foo) for y in range(10)] for x in range(10)]

1
@Nils [foo]*10不会创建10个不同的对象-但在foo是不可变的情况下(例如intor),很容易忽略它们之间的区别str
John La Rooy

137

不要使用[[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)]

效果很好。


26
是的,我也陷入了这个陷阱。这是因为*正在复制address对象(列表)。
chinuy

1
赞成,因为这让我受益。更清楚地说,[[0] * col for _ in range(row)]
Abhijit Sarkar,

62

在Python中初始化二维数组:

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

4
要将所有值初始化为0,只需使用a = [[0 for x in range(columns)] for y in range(rows)]
ZX9

28
[[foo for x in xrange(10)] for y in xrange(10)]

1
的xrange()已删除python3.5
MiaeKim

为什么这样不起作用:[0 * col] *行。当我修改某些元素时,它会在其他地方复制。但是我不明白为什么?
代码muncher

因为那和问题中的代码完全一样。
伊格纳西奥·巴斯克斯

2
@codemuncher [[0] * col] * row不执行所需操作的原因是因为以这种方式初始化2d列表时,Python不会为每一行创建不同的副本。相反,它将使用指向的相同副本的指针来初始化外部列表[0]*col。您对其中一行所做的任何编辑都会反映在其余行中,因为它们实际上都指向内存中的相同数据。
艾迪(Addie)

只是一个想法,但不是所有这些列表都不好附加吗?就是 如果我想要一个尺寸为3 * 6的空2D列表,并想要附加到index [0] [0],[1] [0],[2] [0]等,以填充所有18个元素,则没有这些答案对吗?
mLstudent33 '19

22

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

例如,使用numpy,您将执行以下操作

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

2
虽然numpy很棒,但我认为对于初学者来说可能有点矫kill过正。
EstebanKüber2010年

3
numpy提供了多维数组类型。从列表中构建良好的多维数组是可能的,但对初学者而言,使用numpy的用处不大,难度也更大。嵌套列表对于某些应用程序非常有用,但通常不是想要2D数组的人的最佳选择。
Mike Graham

1
经过几年偶尔做认真的python应用程序之后,标准python数组的怪癖似乎值得继续研究numpy。+1
javadba

12

您可以这样做:

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

11
以我的经验,这种“不希望的”效果通常是一些非常严重的逻辑错误的来源。我认为应该避免这种方法,而@Vipul的答案要好得多。
艾伦·图灵

这种方法行之有效,为什么有人在评论中称其为不良?
布拉沃

1
由于存在副作用,因此您不能真正将其视为矩阵。如果您不需要更改内容,那么就可以了。
hithwen


8

如果它是一个人口稀少的数组,那么最好使用以元组为键的字典:

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

5
t = [ [0]*10 for i in [0]*10]

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


4

错误的方法:[[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的答复。


3
Matrix={}
for i in range(0,3):
  for j in range(0,3):
    Matrix[i,j] = raw_input("Enter the matrix:")

1
尽管此代码可以回答问题,但提供有关此代码为何和/或如何回答问题的其他上下文,可以提高其长期价值。
Ajean


3

使用最简单的思想来创建这个。

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

1

正如@Arnab和@Mike指出的那样,数组不是列表。几乎没有什么不同:1)数组在初始化期间固定大小; 2)数组通常支持的操作少于列表。

在大多数情况下,这可能是一个过大的杀伤力,但这是一个基本的2d数组实现,它利用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])

1

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

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)

1

如果使用numpy,则可以轻松创建2d数组:

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

1
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->
在-> x中对x 求值的最终表达式将是迭代器提供的值
[b表示range(row)中b的值]]->迭代器。

[b代表b在range(row)中的b]],因为row = 5,
所以其计算结果为[0,1,2,3,4],因此现在简化为

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

对于[0,1,2,3,4]中的x,这将计算为[[0] * 5]-> x = 0第一次迭代
[对于[ 0,1,2,3 中的x,[1] * 5, 3,4]]-> x = 1,第2次迭代
[[2] * 5 for x in [0,1,2,3,4]]-> x = 2,第3次迭代
[[3] * 5对于[0,1,2,3,4]中的x – x等于3 =第4次迭代
[[4] * 5对于[0,1,2,3,4]中的x [x] = 4第5次迭代



0

这是一个更简单的方法:

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

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

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

0

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

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


0

可以从以下系列中得出添加尺寸的一般模式:

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以获得指导。
尼克

0

您可以尝试使用此[[0] * 10] * 10。这将返回由10行10列组成的二维数组,每个单元格的值为0。


这本质上是相同的答案stackoverflow.com/a/25601284/2413201 ...
Armali

2
这将创建由10个指向同一行的指针组成的数组。如果这样做a = [[0]*10]*10a[0][0] = 1您将看到每行中的第一个元素现在等于1
andnik


0

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

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

这仅可以保存任何1D,2D值,并将其初始化为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


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

4
请添加一些描述您的代码功能的文本。
whackamadoodle3000

1
通常,最好解释一个解决方案,而不是仅仅发布一些匿名代码行。您可以阅读《我如何写一个好的答案》,也可以解释完全基于代码的答案
Massimiliano Kraus
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.