依赖于 Python 中前一个循环的任意数量的嵌套循环

Posted

技术标签:

【中文标题】依赖于 Python 中前一个循环的任意数量的嵌套循环【英文标题】:Arbitrary number of nested loops dependent on the previous loop in Python 【发布时间】:2021-12-25 23:32:52 【问题描述】:

我试图弄清楚如何迭代任意数量的循环,其中每个循环都依赖于最近的外部循环。以下代码是我想要做的一个例子:

def function(z):
    n = int(log(z))
    tupes = []
    for i_1 in range(1, n):
        for i_2 in range(1, i_1):
            ...
                ...
                    ...
                        for i_n in range(1, i_n - 1):
                            if i_1*i_2*...*i_n > z:
                                tupes.append((i_1, i_2,..., i_n))
    return tupes

虽然我希望它适用于任何z > e**2,但它足以适用于zs 至e**100。我知道,如果我采用适当的ranges 的笛卡尔积,我最终会得到我想要的元组的超集,但我只想获得我寻找的元组。

如果有人能帮我解决这个问题,我将不胜感激。提前致谢。

【问题讨论】:

使用函数和递归。 【参考方案1】:

组合可以升序排列;其实这是itertools.combinations的默认行为。

代码:

for i1 in range(1,6):
    for i2 in range(1,i1):
        for i3 in range(1,i2):
            print (i3, i2, i1)

# (1, 2, 3)
# (1, 2, 4)
# ...
# (3, 4, 5)

相当于代码:

from itertools import combinations

for combination in combinations(range(1,6), 3):
    print combination

# (1, 2, 3)
# (1, 2, 4)
# ...
# (3, 4, 5)

使用组合而不是笛卡尔积将样本空间剔除到您想要的大小。

【讨论】:

【参考方案2】:

您问题中的逻辑是递归实现的(请注意,这允许重复的元组):

import functools

def f(n, z, max_depth, factors=(), depth=0):
    res = []
    if depth == max_depth:
        product = functools.reduce(lambda x, y: x*y, factors, 1)
        if product > z:
            res.append(factors)
    else:
        for i in range(1, n):
            new_factors = factors + (i,)
            res.extend(f(i, z, factors=new_factors, depth=depth+1, max_depth=max_depth))
    return res

z = np.e ** 10
n = int(np.log(z))

print(f(n, z, max_depth=8))

产量

[(8, 7, 6, 5, 4, 3, 2, 1),
 (9, 7, 6, 5, 4, 3, 2, 1),
 (9, 8, 6, 5, 4, 3, 2, 1),
 (9, 8, 7, 5, 4, 3, 2, 1),
 (9, 8, 7, 6, 4, 3, 2, 1),
 (9, 8, 7, 6, 5, 3, 2, 1),
 (9, 8, 7, 6, 5, 4, 2, 1),
 (9, 8, 7, 6, 5, 4, 3, 1),
 (9, 8, 7, 6, 5, 4, 3, 2)]

【讨论】:

我很抱歉花了这么长时间来表达我的感激之情,但显然我的大脑不再正常运作,因为我在我的问题和这个功能上苦苦挣扎。我最终需要一个稍微不同的功能,但总体布局与此相同。非常感谢你的帮助。令人尴尬的是,尽管我尝试将所有 Python 代码重新创建为 Haskell 代码,但我仍然不是递归专家。【参考方案3】:

正如 zondo 建议的那样,您需要使用函数和递归来完成此任务。类似于以下内容的东西应该可以工作:

def recurse(tuplesList, potentialTupleAsList, rangeEnd, z):
    # No range to iterate over, check if tuple sum is large enough
    if rangeEnd = 1 and sum(potentialTupleAsList) > z:
        tuplesList.append(tuple(potentialTupeAsList))
        return
    for i in range(1, rangeEnd):
        potentialTupleAsList.append(i)
        recurse(tuplesList, potentialTupleAsList, rangeEnd - 1, z)
        # Need to remove item you used to make room for new value
        potentialTupleAsList.pop(-1)

然后你可以这样调用它来获得结果:

l = []
recurse(l, [], int(log(z)), z)
print l

【讨论】:

【参考方案4】:

您的最内层循环(如果完全达到)只能超出范围 (1, 1)。由于不包括端点,因此循环不会遍历任何值。因此,您的函数的最短实现是:

def function(z):
    return []

如果您对长度小于 n 的元组感到满意,那么我提出以下解决方案:

import math

def function(z):

    def f(tuples, loop_variables, product, end):
        if product > z:
            tuples.append(loop_variables)

        for i in range(end - 1, 0, -1):
            f(tuples, loop_variables + (i,), product * i, i)
           
    n = int(math.log(z)) 
    tuples = []
    f(tuples, (), 1, n)
    return tuples

虽然时间复杂度并不好:在 O(n) 个元素上使用 n 个嵌套循环,我们大约是 n**n 步。

【讨论】:

以上是关于依赖于 Python 中前一个循环的任意数量的嵌套循环的主要内容,如果未能解决你的问题,请参考以下文章

向量化嵌套循环,其中一个循环变量依赖于另一个

在python中迭代未知数量的嵌套循环

python 利用 for ... else 跳出双层嵌套循环

python 利用 for ... else 跳出双层嵌套循环

Python:动态嵌套for循环,每个循环具有不同的范围

具有不同数量的 For 循环的函数(python)