多个嵌套循环等效于python中的替换

时间:2017-11-17 19:29:26

标签: python loops nested product itertools

我有一个D = {2: 4, 3: 2, 5: 1, 7: 1}形式的简单字典。有4个键是素数,4个值代表最大功率。基于此我想生成表单的所有组合:

  

p1 ^ range1 * p2 ^ range2 * p3 ^ range3 * p4 ^ range4

其中range1range4是与每个素数的字典值对应的范围。对于p1 = 2,范围将为range(0, 4+1)

最简单的方法是嵌套for循环,有四个级别:

for i1 in range(0, 4+1):
   for i2 in range(0, 2+1):
      for i3 in range(0, 1+1):
         for i4 in range(0, 1+1):
            n = 2**i1 * 3**i2 * 5**i3 * 7**i4

这是我想要的,它是正确的,但这是一种非优雅和机械的方式。

另一种方法是使用itertools.product,如果所有范围都相同,则可以使用for x in itertools.product(range(0, 4+1), repeat=4): print(x, end=' ') 。基本上如下:

itertools.product

然而,这将产生所有可能的组合,包括(2,2,3,4), (4,4,2,3)或(2,3,4,4)在我的情况下无效,因为5的幂(元组中的第三个元素)将永远不会是3和7的幂永远不会是4.我想以某种方式限制元素的范围。因此,在这种情况下,最大元组将是(4,2,1,1)对应于幂(字典D中的值)。所以基本上我只需要从(0,0,0,0)到(4,2,1,1)的元组范围。

有没有办法在不使用for循环的情况下实现这一点,并采用与.filter()类似的方法来实现?

非常感谢提前。

2 个答案:

答案 0 :(得分:1)

实际上,

正如 miradulo 所写,解决方案非常简单: 使用:

for x in itertools.product(*map(range, (5, 3, 2, 2))) :
    print(x, end='   ')

或:

for x in itertools.product(range(5), range(3), range(2), range(2)) :
    print(x, end='   ')

两种方式都可以解决问题。

答案 1 :(得分:1)

虽然itertools是要走的路,但这个问题对于练习发电机功能来说是一个很好的练习:

def multirange(d):
    if len(d) == 1:
        for i in range(d[0]):
            yield [i]
    elif len(d) > 1:
        for i in range(d[-1]):
            for a in multirange(d[:-1]):
                yield a + [i]

def multirange_b(d):
    l = len(d)
    products = [1]
    for k in d:
        products.append(products[-1]*k)
    n = products[-1]
    for i in range(n):
        yield [(i%products[j+1])//products[j] for j in range(l)]

for l in multirange([4,3,2]):
    print(l)

for l in multirange_b([4,3,2]):
    print(l)