是否可以定义轻松创建 N 维列表列表的函数?
Is it possible to define function that creates an N-dimensional list of lists easily?
我搜索并发现了这些问题:How to create a multi-dimensional list and 这暗示了我正在寻找的东西,但它们似乎只制作二维数组而不是 ND 数组。
问题:
我的问题是我能够为已知的 n
创建一个 n 维列表列表,但我不确定如何将它推广到 [=17= 的所有值].
考虑这个例子:
def makeList(n):
return [[[n for _ in range(n)]
for _ in range(n)]
for _ in range(n)]
print(makeList(3))
输出:
[[[3, 3, 3],
[3, 3, 3],
[3, 3, 3]],
[[3, 3, 3],
[3, 3, 3],
[3, 3, 3]],
[[3, 3, 3],
[3, 3, 3],
[3, 3, 3]]]
这将创建一个包含 3 个 3 的 3x3x3 数组的列表列表,这是预期的结果,但是如果我们使用不同的 n
:
print(makeList(2))
输出:
[[[2, 2],
[2, 2]],
[[2, 2],
[2, 2]]]
这将创建一个由 2 个 2 组成的 2x2x0 数组的列表列表,这不是预期的结果。相反,结果应该是一个由 2 组成的 2x2 数组的列表列表。
同样,如果我们设置 n = 4:
print(makeList(4))
当它应该给出 4x4x4x4 的列表列表时,它会给出一个 4x4x4 的列表列表。
主要问题是 for
循环的数量必须根据输入而改变,但显然代码不能“复活”并神奇地自行重新编码,因此我的问题。
我正在寻找一种简单的方法来获得这个结果。我确信我可以继续开发解决方案的想法,但我还没有想到任何简洁的东西。
我试过的:
我第一个想到的想法是使用递归,这是我的简单方法:
def makeList(n, output = []):
if not output:
output = [n for _ in range(n)]
else:
output = [output for _ in range(n)]
if len(output) == n:
return output
else:
return makeList(n, output)
这显然行不通,因为 if len(output) == n:
将执行第一次迭代,因为内部循环的长度等于最外层循环的长度。然而,即使有一个条件可以正确终止函数,这个解决方案仍然不是理想的,因为我可以 运行 进入具有大值 n
的最大递归错误。此外,即使这些问题得到解决,此代码仍然很长且耗时。
我考虑的另一个潜在观点(以及我发现有效的解决方案)是使用 dict
。我的解决方案将列表的中间列表保存在 dict
中,以便可以用于下一次迭代:
def makeList(n):
d = {str(i): None for i in range(n)}
for i in range(n):
if i == 0:
d[str(i)] = [n for _ in range(n)]
else:
d[str(i)] = [d[str(i-1)] for _ in range(n)]
return d[str(n-1)]
但同样,这很长而且看起来不是很 pythonic。
解法要求:
理想的解决方案将比我的更简洁,具有仅使用内置函数的高效时间复杂度。
只要答案的精神是尽力满足要求,其他接近这些要求的选项也会有所帮助。
然而,简洁是最重要的方面,这就是为什么我对目前的尝试并不完全满意。
您的最佳计划是为此使用 numpy
。您可以使用 np.zeros( (4,4,4) )
创建一个全为 0 的任意数组,或者使用 np.ones( (4,4,4) )
创建一个全为 1 的数组。如果你要经常使用数组,你肯定会想要使用 numpy
.
我已经草拟了一个可能适合的递归函数:
def nd_list(n, x=None):
if x is None:
x = n
if x == 1:
return [n] * n
return [nd_list(n, x-1)] * n
两行不使用外部库!
def nd_list(x, z):
return [z] * z if x == 1 else [nd_list(x-1, z)] * z
两行(仅)且没有 list of lists surprising behaviour:
def nd_list(x, z):
return [0 for _ in range(z)] if x == 1 else [nd_list(x-1, z) for _ in range(z)]
用tuple(n for _ in range(n))
获取你想要的维度,用numpy生成多维数组:
import numpy as np
def make_array(n):
return np.full(tuple(n for _ in range(n)), n)
for n in range(1,5):
print(make_array(n))
输出:
[1]
[[2 2]
[2 2]]
[[[3 3 3]
[3 3 3]
[3 3 3]]
[[3 3 3]
[3 3 3]
[3 3 3]]
[[3 3 3]
[3 3 3]
[3 3 3]]]
[[[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]
[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]
[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]
[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]]
[[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]
[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]
[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]
[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]]
[[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]
[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]
[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]
[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]]
[[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]
[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]
[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]
[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]]]
使用 python 模式匹配支持
def nlist(shape: tuple[int, ...], fill_with=None):
match shape:
case (n,):
return [fill_with] * n
case (n, *rest):
return [nlist(rest, fill_with) for _ in range(n)]
case _:
raise ValueError(f'Invalid value shape={shape}')
def makeList(n):
return nlist((n,)*n, n)
我的意思是,我喜欢 numpy 和所有东西,但如果我想进行一般的动态编程,我不想 pip install
一个庞大的库。对于需要复杂 DP 的技术面试也会很吃力。
这是一个简单易读的函数,它利用了 Python 中的 built-in itertools
模块(它使用 repeat
)和 copy
模块用于制作列表的深层副本(否则,您会看到修改一个条目会修改多个条目的“令人惊讶的”列表行为)。它在 API 方面也很正常:你可以用维度元组调用它(比如 numpy 数组的 shape
字段):
from itertools import repeat
from copy import deepcopy
def ndarray(shape, val=None):
base = val
for dim in reversed(shape):
base = list(map(deepcopy, repeat(base, times=dim)))
return base
这是制作的:
>>> import pprint
>>> pprint.pprint(ndarray((2, 3, 4), val=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]]]
对于您原来的问题,您可以轻松地 makeList(n)
围绕这个问题:
def makeList(n, val=None):
return ndarray([n]*n, val=val)
我搜索并发现了这些问题:How to create a multi-dimensional list and
问题:
我的问题是我能够为已知的 n
创建一个 n 维列表列表,但我不确定如何将它推广到 [=17= 的所有值].
考虑这个例子:
def makeList(n):
return [[[n for _ in range(n)]
for _ in range(n)]
for _ in range(n)]
print(makeList(3))
输出:
[[[3, 3, 3],
[3, 3, 3],
[3, 3, 3]],
[[3, 3, 3],
[3, 3, 3],
[3, 3, 3]],
[[3, 3, 3],
[3, 3, 3],
[3, 3, 3]]]
这将创建一个包含 3 个 3 的 3x3x3 数组的列表列表,这是预期的结果,但是如果我们使用不同的 n
:
print(makeList(2))
输出:
[[[2, 2],
[2, 2]],
[[2, 2],
[2, 2]]]
这将创建一个由 2 个 2 组成的 2x2x0 数组的列表列表,这不是预期的结果。相反,结果应该是一个由 2 组成的 2x2 数组的列表列表。
同样,如果我们设置 n = 4:
print(makeList(4))
当它应该给出 4x4x4x4 的列表列表时,它会给出一个 4x4x4 的列表列表。
主要问题是 for
循环的数量必须根据输入而改变,但显然代码不能“复活”并神奇地自行重新编码,因此我的问题。
我正在寻找一种简单的方法来获得这个结果。我确信我可以继续开发解决方案的想法,但我还没有想到任何简洁的东西。
我试过的:
我第一个想到的想法是使用递归,这是我的简单方法:
def makeList(n, output = []):
if not output:
output = [n for _ in range(n)]
else:
output = [output for _ in range(n)]
if len(output) == n:
return output
else:
return makeList(n, output)
这显然行不通,因为 if len(output) == n:
将执行第一次迭代,因为内部循环的长度等于最外层循环的长度。然而,即使有一个条件可以正确终止函数,这个解决方案仍然不是理想的,因为我可以 运行 进入具有大值 n
的最大递归错误。此外,即使这些问题得到解决,此代码仍然很长且耗时。
我考虑的另一个潜在观点(以及我发现有效的解决方案)是使用 dict
。我的解决方案将列表的中间列表保存在 dict
中,以便可以用于下一次迭代:
def makeList(n):
d = {str(i): None for i in range(n)}
for i in range(n):
if i == 0:
d[str(i)] = [n for _ in range(n)]
else:
d[str(i)] = [d[str(i-1)] for _ in range(n)]
return d[str(n-1)]
但同样,这很长而且看起来不是很 pythonic。
解法要求:
理想的解决方案将比我的更简洁,具有仅使用内置函数的高效时间复杂度。
只要答案的精神是尽力满足要求,其他接近这些要求的选项也会有所帮助。
然而,简洁是最重要的方面,这就是为什么我对目前的尝试并不完全满意。
您的最佳计划是为此使用 numpy
。您可以使用 np.zeros( (4,4,4) )
创建一个全为 0 的任意数组,或者使用 np.ones( (4,4,4) )
创建一个全为 1 的数组。如果你要经常使用数组,你肯定会想要使用 numpy
.
我已经草拟了一个可能适合的递归函数:
def nd_list(n, x=None):
if x is None:
x = n
if x == 1:
return [n] * n
return [nd_list(n, x-1)] * n
两行不使用外部库!
def nd_list(x, z):
return [z] * z if x == 1 else [nd_list(x-1, z)] * z
两行(仅)且没有 list of lists surprising behaviour:
def nd_list(x, z):
return [0 for _ in range(z)] if x == 1 else [nd_list(x-1, z) for _ in range(z)]
用tuple(n for _ in range(n))
获取你想要的维度,用numpy生成多维数组:
import numpy as np
def make_array(n):
return np.full(tuple(n for _ in range(n)), n)
for n in range(1,5):
print(make_array(n))
输出:
[1]
[[2 2]
[2 2]]
[[[3 3 3]
[3 3 3]
[3 3 3]]
[[3 3 3]
[3 3 3]
[3 3 3]]
[[3 3 3]
[3 3 3]
[3 3 3]]]
[[[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]
[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]
[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]
[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]]
[[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]
[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]
[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]
[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]]
[[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]
[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]
[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]
[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]]
[[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]
[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]
[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]
[[4 4 4 4]
[4 4 4 4]
[4 4 4 4]
[4 4 4 4]]]]
使用 python 模式匹配支持
def nlist(shape: tuple[int, ...], fill_with=None):
match shape:
case (n,):
return [fill_with] * n
case (n, *rest):
return [nlist(rest, fill_with) for _ in range(n)]
case _:
raise ValueError(f'Invalid value shape={shape}')
def makeList(n):
return nlist((n,)*n, n)
我的意思是,我喜欢 numpy 和所有东西,但如果我想进行一般的动态编程,我不想 pip install
一个庞大的库。对于需要复杂 DP 的技术面试也会很吃力。
这是一个简单易读的函数,它利用了 Python 中的 built-in itertools
模块(它使用 repeat
)和 copy
模块用于制作列表的深层副本(否则,您会看到修改一个条目会修改多个条目的“令人惊讶的”列表行为)。它在 API 方面也很正常:你可以用维度元组调用它(比如 numpy 数组的 shape
字段):
from itertools import repeat
from copy import deepcopy
def ndarray(shape, val=None):
base = val
for dim in reversed(shape):
base = list(map(deepcopy, repeat(base, times=dim)))
return base
这是制作的:
>>> import pprint
>>> pprint.pprint(ndarray((2, 3, 4), val=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]]]
对于您原来的问题,您可以轻松地 makeList(n)
围绕这个问题:
def makeList(n, val=None):
return ndarray([n]*n, val=val)