【问题标题】:Conditionally use parts of a nested for loop有条件地使用嵌套 for 循环的一部分
【发布时间】:2021-01-24 00:28:50
【问题描述】:

我已经广泛搜索了这个答案,但似乎找不到答案。因此,我第一次在这里发布问题。

我有一个使用许多参数来执行计算的函数。根据用户输入,我想遍历部分(或全部)参数的可能值。如果我想遍历所有参数,我可能会这样做:

for i in range(low1,high1):
    for j in range(low2,high2):
        for k in range(low3,high3):
            for m in range(low4,high4):
                doFunction(i, j, k, m)

如果我只想迭代第一个和第四个参数,我可能会这样做:

for i in range(low1,high1):
    for m in range(low4,high4):
        doFunction(i, user_input_j, user_input_k, m)

我的实际代码有将近 15 个嵌套的 for 循环,其中包含 15 个不同的参数——每个参数都可以是可迭代的(或不可迭代的)。因此,对于我来说,使用我拥有的东西并为参数的每个组合是否可迭代编写一个独特的 for 循环块是不可扩展的。如果我这样做,我将拥有 2^15 个不同的代码块。

我可以这样做:

if use_static_j == True:
    low2  = -999
    high2 = -1000
for i in range(low1,high1):
    for j in range(low2,high2):
        for k in range(low3,high3):
            for m in range(low4,high4):
                j1 = j if use_static_j==False else user_input_j
                doFunction(i, j1, k, m)

我只是想知道是否有更好的方法。也许使用 filter()、map() 或列表理解......(我还没有足够清楚的理解)

【问题讨论】:

  • 很遗憾,我真的不能帮助你,但是我想分享一个我过去使用过的方法。如果您必须有条件地使用循环,您可以尝试通过将选项映射到从所有选项构建的笛卡尔数组中的索引来构建仅使用单个循环的结构。因此,如果您的选项 a 在 0-9 范围内,选项 b 在 0-4 范围内,您将迭代 0-49 并将选项 a 设置为迭代 / 5,将选项 b 设置为迭代 % 5
  • 我想过做这样的事情,但很难考虑 15 个不同的参数。除此之外,范围可能是负数,而且我实际上可能有额外的输入来指定范围的“步骤”。例如,-90 到 90 度,步长为 0.1...
  • param = param_min + (index % (multiplied 'inner loop' param ranges)) * step_size 参数范围为(param_max - param_min) / stepsize,不是吗?
  • 我发现这个问题似乎在同一个方向stackoverflow.com/questions/31362507/… 另外,这可能是一个最好通过递归解决的问题。

标签: python-3.x loops for-loop filter list-comprehension


【解决方案1】:

按照 cmets 中的建议,您可以构建一个参数数组,然后使用数组中的每个值调用函数。构建数组的最简单方法是对定义每个参数范围的列表使用递归。在这段代码中,我假设了一个由startstopscale 参数组成的元组列表(例如,列表中的第三个元素产生[3, 2.8, 2.6, 2.4, 2.2])。要使用静态值,您可以使用元组 (static, static+1, 1)

def build_param_array(ranges):
    r = ranges[0]
    if len(ranges) == 1:
        return [[p * r[2]] for p in range(r[0], r[1], -1 if r[1] < r[0] else 1)]
    res = []
    for p in range(r[0], r[1], -1 if r[1] < r[0] else 1):
        pa = build_param_array(ranges[1:])
        for a in pa:
            res.append([p * r[2]] + a)
    return res

# range = (start, stop, scale)
ranges = [(1, 5, 1),
          (0, 10, .1),
          (15, 10, .2)
          ]

params = build_param_array(ranges)

for p in params:
    doFunction(*p)

【讨论】:

  • 这确实有效。但现在我有一个新问题。使用这种方法,如果我启用所有选项,程序会因内存错误而终止。如果我不启用所有选项,我会将此问题视为单独的问题,因为您的答案确实有效。
  • @DavidSteele 是的,这就是这里的问题,如果您有大量选项,您最终可能会生成一个相当大的数组。解决此问题的一种方法是嵌套此代码的多个循环,例如,将您的选项集分成 4 个组并为每个组构建参数数组,然后您只需要 4 个嵌套的 for 循环来处理 16选项。
  • 再次感谢尼克。我现在正在试验它 - 以及 memmap 和 h5py 等其他选项。
  • 试图理解范围[1:]...这是切片?
  • @DavidSteele 是的 - ranges[1:] 基本上是所有 ranges 列表,不包括第一个元素 (ranges[0])
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-11
  • 2018-07-24
  • 2021-04-29
  • 1970-01-01
  • 2015-06-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多