使用Python创建3D数组

53

我想在Python (2.7) 中创建一个三维数组,以便像这样使用:

distance[i][j][k]

数组的大小应该是我拥有的变量的大小。(nnn)

我尝试使用:

distance = [[[]*n]*n]

但那似乎不起作用。

我只能使用默认库,并且乘法方法(即[[0]*n]*n)无法使用,因为它们链接到同一指针,而我需要所有值都是独立的。


考虑使用标准的 array 模块的 array 类。 - martineau
11个回答

81
你应该使用列表推导式:list comprehension
>>> import pprint
>>> n = 3
>>> distance = [[[0 for k in xrange(n)] for j in xrange(n)] for i in xrange(n)]
>>> pprint.pprint(distance)
[[[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]]]
>>> distance[0][1]
[0, 0, 0]
>>> distance[0][1][2]
0

您尝试的语句可以生成一个数据结构,但由于内部列表是按引用复制的,因此它会产生副作用:

>>> distance=[[[0]*n]*n]*n
>>> pprint.pprint(distance)
[[[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]]]
>>> distance[0][0][0] = 1
>>> pprint.pprint(distance)
[[[1, 0, 0], [1, 0, 0], [1, 0, 0]],
 [[1, 0, 0], [1, 0, 0], [1, 0, 0]],
 [[1, 0, 0], [1, 0, 0], [1, 0, 0]]]

1
对于Python3,您可以将xrange更改为range。 - csteel
我在不知情的情况下使用了“按引用复制”的方法,因此最终出现了“副作用”(我的变量中所有字段最终都具有相同的值),并且不知道原因。感谢您的解释。 - Mihaela Grigore

51

numpy.array专门为这种情况设计:

 numpy.zeros((i,j,k))

这将为您提供一个由零填充的 ijk 维度的数组。

根据您需要它的用途,numpy 可能是您所需的正确库。


哦,我以为这是默认库之一。我不能使用除此以外的任何东西。 - Laís Minchillo
3
不幸的是,它是一个外部库。但如果你需要处理(大量的)数字数据数组,通常非常合适,特别是在速度方面。 - mata
我这样定义一个数组:new_array= numpy.zeros((6340,200,200)),但它在内存中占用了1.9GB的空间。这正常吗? - gocen
@gocen 是的,听起来没错。Numpy零返回的默认值是numpy.float64,而6340200200*64bits = 2.0288千兆字节。您可以向zeros提供一个额外的参数'dtype'来更改它返回的类型,并以此方式节省一些RAM。 - Filip Franik

9
正确的做法是:
[[[0 for _ in range(n)] for _ in range(n)] for _ in range(n)]

你想要做的事情应该像这样写(对于NxNxN)

[[[0]*n]*n]*n

但那是不正确的,见@Adaman评论说明为什么。

5
不好。它会包含对同一数组的引用。尝试这个:a = [[0] * 3 for i in range(3)]; a[0][0] = 1; print(a) - Amadan

5
"""
Create 3D array for given dimensions - (x, y, z)

@author: Naimish Agarwal
"""


def three_d_array(value, *dim):
    """
    Create 3D-array
    :param dim: a tuple of dimensions - (x, y, z)
    :param value: value with which 3D-array is to be filled
    :return: 3D-array
    """

    return [[[value for _ in xrange(dim[2])] for _ in xrange(dim[1])] for _ in xrange(dim[0])]

if __name__ == "__main__":
    array = three_d_array(False, *(2, 3, 1))
    x = len(array)
    y = len(array[0])
    z = len(array[0][0])
    print x, y, z

    array[0][0][0] = True
    array[1][1][0] = True

    print array

建议使用numpy.ndarray来处理多维数组。


5
d3 = [[[0 for col in range(4)]for row in range(4)] for x in range(6)]

d3[1][2][1]  = 144

d3[4][3][0]  = 3.12

for x in range(len(d3)):
    print d3[x]



[[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, 144, 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], [3.12, 0, 0, 0]]
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]

4

您还可以使用嵌套的for循环,如下所示:

n = 3
arr = []
for x in range(n):
    arr.append([])
    for y in range(n):
        arr[x].append([])
        for z in range(n):
            arr[x][y].append(0)
print(arr)

1

I just want notice that

distance = [[[0 for k in range(n)] for j in range(n)] for i in range(n)]

可以缩短为

distance = [[[0] * n for j in range(n)] for i in range(n)]

1
n1=np.arange(90).reshape((3,3,-1))
print(n1)
print(n1.shape)

1

有很多方法可以解决你的问题。

  1. 首先是由@robert接受的答案。这是它的通用解决方案:
def multi_dimensional_list(value, *args):
  #args dimensions as many you like. EG: [*args = 4,3,2 => x=4, y=3, z=2]
  #value can only be of immutable type. So, don't pass a list here. Acceptable value = 0, -1, 'X', etc.
  if len(args) > 1:
    return [ multi_dimensional_list(value, *args[1:]) for col in range(args[0])]
  elif len(args) == 1: #base case of recursion
    return [ value for col in range(args[0])]
  else: #edge case when no values of dimensions is specified.
    return None

例如:

>>> multi_dimensional_list(-1, 3, 4)  #2D list
[[-1, -1, -1, -1], [-1, -1, -1, -1], [-1, -1, -1, -1]]
>>> multi_dimensional_list(-1, 4, 3, 2)  #3D list
[[[-1, -1], [-1, -1], [-1, -1]], [[-1, -1], [-1, -1], [-1, -1]], [[-1, -1], [-1, -1], [-1, -1]], [[-1, -1], [-1, -1], [-1, -1]]]
>>> multi_dimensional_list(-1, 2, 3, 2, 2 )  #4D list
[[[[-1, -1], [-1, -1]], [[-1, -1], [-1, -1]], [[-1, -1], [-1, -1]]], [[[-1, -1], [-1, -1]], [[-1, -1], [-1, -1]], [[-1, -1], [-1, -1]]]]

附言:如果您想对参数进行正确值的验证,例如仅限自然数,则可以在调用此函数之前编写包装函数。

  1. 其次,任何多维数组都可以写成单维数组。这意味着您不需要多维数组。以下是索引转换的函数:
def convert_single_to_multi(value, max_dim):
  dim_count = len(max_dim)
  values = [0]*dim_count
  for i in range(dim_count-1, -1, -1): #reverse iteration
    values[i] = value%max_dim[i]
    value /= max_dim[i]
  return values


def convert_multi_to_single(values, max_dim):
  dim_count = len(max_dim)
  value = 0
  length_of_dimension = 1
  for i in range(dim_count-1, -1, -1): #reverse iteration
    value += values[i]*length_of_dimension
    length_of_dimension *= max_dim[i]
  return value

由于这些函数是彼此的反函数,因此这是输出:

>>> convert_single_to_multi(convert_multi_to_single([1,4,6,7],[23,45,32,14]),[23,45,32,14])
[1, 4, 6, 7]
>>> convert_multi_to_single(convert_single_to_multi(21343,[23,45,32,14]),[23,45,32,14])
21343

如果您关心性能问题,那么可以使用一些库,如pandas、numpy等。

0
def n_arr(n, default=0, size=1):
    if n is 0:
        return default

    return [n_arr(n-1, default, size) for _ in range(size)]

arr = n_arr(3, 42, 3)
assert arr[2][2][2], 42

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接