如何在 Python 中初始化一个二维数组?
Posted
技术标签:
【中文标题】如何在 Python 中初始化一个二维数组?【英文标题】:How to initialize a two-dimensional array in 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 = []
它给出了预期的结果,但感觉像是一种解决方法。有没有更简单/更短/更优雅的方法来做到这一点?
【问题讨论】:
只是一个小的(或重要的,取决于谁在看)挑剔:列表不是数组。如果你想要数组,请使用 numpy。 This question is similar:讨论了Python中多维数组的初始化。 @ArnabDatta 那么你将如何在 numpy 中初始化一个多维数组呢? @AndersonGreen docs.scipy.org/doc/numpy/user/… 您可以在默认 Python 中将数据排列在类似结构的数组中,但它不如 NumPy 数组高效或有用。特别是如果您想处理大型数据集。这是一些文档docs.scipy.org/doc/numpy-1.10.1/user/basics.creation.html 【参考方案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
为列,我认为最好在你的语法中交换 i
和 j
以便更好地理解并将范围更改为 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
返回foo
s
[[Foo() for x in range(10)] for y in range(10)]
【讨论】:
@Mike,你错过了粗体部分吗?如果 foo 是可变的,那么这里的其他答案都不起作用(除非你根本没有改变 foo) 您无法使用copy.deepcopy
正确复制任意对象。如果你有一个任意的可变对象,你需要一个特定于你的数据的计划。
如果您在循环中非常需要速度,可能是时候使用 Cython、weave 或类似的...
@JohnLaRooy 我认为你互换了x
和y
。不应该是[[copy.deepcopy(foo) for y in range(10)] for x in range(10)]
@Nils [foo]*10
不会创建 10 个不同的对象 - 但很容易忽略 foo 不可变情况下的差异,例如 int
或 str
。【参考方案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。这个问题已经有一个被大量接受的答案。乍一看,这篇文章实际上并没有回答这个问题。请参阅***.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))
【讨论】:
请添加一些文字来描述您的代码的作用。 通常最好解释一个解决方案,而不是仅仅发布一些匿名代码行。你可以阅读How do I write a good answer,也可以阅读Explaining entirely code-based answers。以上是关于如何在 Python 中初始化一个二维数组?的主要内容,如果未能解决你的问题,请参考以下文章