生成由动态长度列表组成的动态长度列表

Generating a list of dynamic length consisting of lists of dynamic lengths

我想要一种高效、简洁的方法来在 Python (3.9) 中生成以下子列表列表,这让我很困惑。我敢肯定,对大多数人来说都是儿戏,但我显然只是在婴幼儿游戏中。

变量将是(括号中使用默认值):

最后我会添加一个检查,如果 sum(sublist) 在两个变量值之间,子列表仅附加到列表,所以我最终得到满足某些条件的排列列表。这些标准可能包括更改 y 的值以控制迭代的绝对数量。

[
[25],
[45],
[65],
[25,25],
[45,25],
[65,25],
[25,45],
...
[45,65],
[65,65],
[25,25,25],
[45,25,25],
...
[45,65,65],
[65,65,65]
]

您可以对每个长度子集使用 itertools.product(),然后使用 itertools.chain() 将列表连接在一起。

def get_lists(a, x, y, z, m=float('-inf'), n=float('inf')):
    v = list(range(x, z, y))
    return list(itertools.chain(*(
        (
            list(reversed(p))
            for p in itertools.product(*([v] * i)) 
            if m < sum(p) < n
        ) for i in range(1, a + 1)
    )))

如果需要,这也可以考虑下限和上限,可选参数 mn。如果没有给出,那么一切都应该在无穷大和负无穷大之间。

这里使用了一些技巧。

  • 首先,itertools.product() 将以您想要的相反顺序显示(它首先改变最后一个元素,而您首先改变第一个元素)。所以我们将它输入 reversed()itertools.product() 通常也会生成元组而不是列表,但是由于我们必须将迭代器 reversed() returns 强制转换为列表,所以没有问题。如果你不关心这个,你可以省略最里面的list(reversed(p)),直接留在p。或者,如果您根本不关心过滤输入,您可以完全删除内部理解。
  • 其次,在 itertools.product()itertools.chain() 中,我们使用参数解包运算符 * 将整个列表作为位置参数传递。对于 itertools.product(),这只是根据需要多次复制 'eligible values' 范围,而对于 itertools.chain(),它将每个 itertools.product() 的各个输出拼接在一起。很多itertools滥用都需要这个成语。

否则这只是一些嵌套理解。从技术上讲,您可以在一行中完成,但我发现将 v 放入变量中并执行 [v] * i 比执行 (range(x, z, y) for _ in range(i)).

更好