生成按增加的最大项目顺序排序的组合(实际上是产品)

时间:2015-01-04 01:47:29

标签: python

下面的第一个功能是我想要的,但效率不高。

它生成有序的产品,以便稍后生成包含更大元素的列表。

第一个不必要地生成被丢弃的组合。如何提高效率?一个更好的算法会很好。

import itertools

def prods(base, length, start = 0):
  for b in xrange(start + 1, base + 1):
    for comb in [list(reversed(item)) for item in itertools.product(xrange(b), repeat = length)]:
      if max(comb) == (b - 1):
        yield comb

>>> for val in prods(3, 2): print val
[0, 0]  # 0's start here
[1, 0]  # 1's start here
[0, 1]
[1, 1]
[2, 0]  # 2's start here
[2, 1]
[0, 2]
[1, 2]
[2, 2]

>>> for val in prods(3, 2, 2): print val
[2, 0]  # 2's start here
[2, 1]
[0, 2]
[1, 2]
[2, 2]

这是另一个(部分)解决方案,它的内存效率不高,但没有任何内容被丢弃。

import itertools

def prods2(base, length):
  for comb in sorted([list(reversed(item)) for item in itertools.product(xrange(base), repeat = length)], key=max):
    yield comb

>>> for val in prods2(3, 2): print val
[0, 0]  # 0's start here
[1, 0]  # 1's start here
[0, 1]
[1, 1]
[2, 0]  # 2's start here
[2, 1]
[0, 2]
[1, 2]
[2, 2]

顺便问一下,这样的排序是否有名称?

2 个答案:

答案 0 :(得分:0)

这似乎可以解决问题:

from itertools import product

vs = range(3)

def compare(x,y):

    mx = cmp(max(x), max(y))
    sc = cmp(x[1], y[1])

    if mx == 0:
         return sc
    return mx

for p in sorted(product(vs, vs), cmp=compare):
    print p

您想首先比较最大值。如果存在平局,则比较第二个值,最后比较第一个值。

排序不是度反向词典排序,因为您比较元组的最大值而不是总和。我想你可以称它为指数反向词典排序;但请不要引用我。

答案 1 :(得分:0)

我原本想完全独立于itertools写这个,但实际上我做得太多了。 itertools的优点在于它全部基于生成器,因此不会存储任何内容。因此,我们实际上可以多次运行itertools.product,并根据结果的内容进行过滤。

那么我们如何解决这个问题呢?我们首先从[0]获得所有组合。然后我们从[0, 1]获取所有组合。然后我们从[0, 1, 2]等获得所有 new 组合。我们只需要确保正确完成“新”部分。为此,我们只需要确保最高数字是组合的一部分。

def prods (num, length):
    for i in range(num + 1):
        # get all product combinations …
        for c in itertools.product(range(i + 1), repeat=length):
            # … but only select the ones where the current number is contained
            if i in c:
                yield c

这导致了一个略微不同的顺序(实际上对我来说更有意义),但总体思路仍然存在:

>>> for x in prods(3, 2):
        print(x)

(0, 0) # <- 0 starts
(0, 1) # <- 1 starts
(1, 0)
(1, 1)
(0, 2) # <- 2 starts
(1, 2)
(2, 0)
(2, 1)
(2, 2)
(0, 3) # <- 3 starts
(1, 3)
(2, 3)
(3, 0)
(3, 1)
(3, 2)
(3, 3)