以不同顺序迭代itertools.product而不创建列表

时间:2016-10-07 12:40:11

标签: python algorithm dynamic-programming combinatorics itertools

我有一个可迭代的,它涵盖了巨大的搜索空间。我的计划不是让脚本终止,而是在一段时间之后杀死它。

现在我需要这个空间的笛卡尔积并在那里搜索。 itertools.product生成此订单:

>>> list(itertools.product(range(3), repeat=2))
[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]

虽然我想以类似于:

的对角线顺序搜索
[(0, 0), (0, 1), (1, 0), (0, 2), (1, 1), (2, 0), (1, 2), (2, 1), (2, 2)]
带有一些返回元组元素总和的关键函数的

sorted将是我的常规方法,但是对于排序所有数据都需要检查,这在我的情况下是不可行的。有没有办法做到这一点?

此问题与this one非常相似,但答案中仍然使用sorted。另外,我不会很快看到如何使ordered_combinations适应ordered_product

2 个答案:

答案 0 :(得分:0)

这个问题等同于询问如何使用给定总和为连续和增加的总和值创建所有n元组:

                  (0, 0),               sum == 0
              (0, 1), (1, 0),           sum == 1
        (0, 2), (1, 1), (2, 0),         sum == 2
             (1, 2), (2, 1),            sum == 3
                  (2, 2)                sum == 4

对于任何给定的行(具有给定的目标总和),子问题等同于动态编程问题Number of ways to make change for amount NNumber of ways to add up to a sum S with N numbers

另见Donald Knuth在Combinatorial Algorithms中的写作。

答案 1 :(得分:0)

实际上很容易计算repeat=2案例对角线的索引:

def diagonal_product(inp):
    inp = tuple(inp)
    n = len(inp)
    # upper left triangle
    for i in range(n):
        for j in range(i+1):
            yield inp[i-j], inp[j]
    # lower right triangle
    for i in range(1, n):
        for j in range(n-i):
            yield inp[n-j-1], inp[i+j]

只是为了显示结果:

>>> list(diagonal_product(range(4)))
[(0, 0), (1, 0), (0, 1), (2, 0), (1, 1), (0, 2), (3, 0), (2, 1), (1, 2), 
 (0, 3), (3, 1), (2, 2), (1, 3), (3, 2), (2, 3), (3, 3)]

>>> list(diagonal_product(range(3)))
[(0, 0), (1, 0), (0, 1), (2, 0), (1, 1), (0, 2), (2, 1), (1, 2), (2, 2)]

函数本身可能比它需要的更复杂(或更慢),但我还没有为这种情况找到任何参考实现。

如果输入range,您还可以避免所有索引,只返回索引:

def diagonal_product(n):
    # upper left triangle
    for i in range(n):
        for j in range(i+1):
            yield i-j, j
    # lower right triangle
    for i in range(1, n):
        for j in range(n-i):
            yield n-j-1, i+j

list(diagonal_product(3))
# [(0, 0), (1, 0), (0, 1), (2, 0), (1, 1), (0, 2), (2, 1), (1, 2), (2, 2)]