Python中有序子集的有效枚举

Python中有序子集的有效枚举,python,iterator,generator,combinations,itertools,Python,Iterator,Generator,Combinations,Itertools,我不确定我正在尝试编写的代码的数学术语是否合适。我想生成唯一整数的组合,其中每个组合的“有序子集”用于排除某些以后的组合 希望有一个例子能说明这一点: from itertools import chain, combinations ​ mylist = range(4) max_depth = 3 rev = chain.from_iterable(combinations(mylist, i) for i in xrange(max_depth, 0, -1)) for el in li

我不确定我正在尝试编写的代码的数学术语是否合适。我想生成唯一整数的组合,其中每个组合的“有序子集”用于排除某些以后的组合

希望有一个例子能说明这一点:

from itertools import chain, combinations
​
mylist = range(4)
max_depth = 3

rev = chain.from_iterable(combinations(mylist, i) for i in xrange(max_depth, 0, -1))
for el in list(rev):
    print el

该代码生成的输出包含我想要的所有子集,但也包含一些我不想要的额外子集。我已手动插入注释,以指示我不需要的元素

(0, 1, 2)
(0, 1, 3)
(0, 2, 3)
(1, 2, 3)
(0, 1)  # Exclude: (0, 1, _) occurs as part of (0, 1, 2) above
(0, 2)  # Exclude: (0, 2, _) occurs above
(0, 3)  # Keep
(1, 2)  # Exclude: (1, 2, _) occurs above
(1, 3)  # Keep: (_, 1, 3) occurs above, but (1, 3, _) does not
(2, 3)  # Keep
(0,)    # Exclude: (0, _, _) occurs above
(1,)    # Exclude: (1, _, _) occurs above
(2,)    # Exclude: (2, _) occurs above
(3,)    # Keep

因此,我的生成器或迭代器的期望输出是:

(0, 1, 2)
(0, 1, 3)
(0, 2, 3)
(1, 2, 3)
(0, 3)
(1, 3)
(2, 3)
(3,)  

我知道我可以列出所有(想要的和不想要的)组合,然后过滤掉我不想要的组合,但我想知道是否有一种更有效的、基于生成器或迭代器的方法。

我注意到您想要的输出中有一种有趣的模式,我有一个生成器可以产生这种模式。这对你所有的案子都有效吗

from itertools import combinations

def orderedSetCombination(iterable, r):
    # Get the last element of the iterable
    last = (iterable[-1], )
    # yield all the combinations of the iterable without the
    # last element
    for iter in combinations(iterable[:-1], r):
        yield iter
    # while r > 1 reduce r by 1 and yield all the combinations
    while r>1:
        r -= 1
        for iter in combinations(iterable[:-1], r):
            yield iter+last
    # yield the last item
    yield last

iter = [0,1,2,3]

for el in (list(orderedSetCombination(iter, 3))):
    print(el)
以下是我对逻辑的解释:

# All combinations that does not include the last element of the iterable
# taking r = max_depth items at a time

(0,1,2) 

# from here on, its the combinations of all the elements except 
# the last element and the last element is added to it.
# so here taking r = r -1 items at a time and adding the last element
# combinations([0,1,2], r=2)

(0,1,3)
(0,2,3)
(1,2,3)

# the only possible value right now at index r = 2 is the last element (3)
# since all possible values of (0,1,_) (0,2,_) (1,2,_) are already listed
# So reduce r by 1 again and continue: combinations([0,1,2], r=1)

(0, 3)
(1, 3)
(2, 3)

# continue until r == 0 and then yield the last element

(3,)

您正试图排除作为先前返回的组合前缀的任何组合。这样做很简单

  • 如果元组
    t
    具有长度
    max_depth
    ,则它不能是先前返回的元组的前缀,因为它作为前缀的任何元组都必须更长
  • 如果元组
    t
    mylist[-1]
    结尾,那么它不能是先前返回的元组的前缀,因为没有可以合法地添加到
    t
    结尾以扩展它的元素
  • 如果元组
    t
    的长度小于
    max_depth
    ,并且没有以
    mylist[-1]
    结尾,则
    t
    是先前返回的元组
    t+(mylist[-1],)
    的前缀,并且不应返回
    t
因此,您应该生成的组合正好是长度
max_depth
和以
mylist[-1]
结尾的较短组合。下面的代码执行此操作,其顺序与原始代码完全相同,并且正确处理了类似
maxdepth>len(mylist)


(我在这里假设,在
maxdepth==0
的情况下,您仍然不希望在输出中包含空元组,即使对于
maxdepth==0
,它不是先前返回的元组的前缀。如果在这种情况下确实需要空元组,则可以更改
(iterable和maxlen)
如果不可编辑

您可以将所有子集散列到字典中。因此,如果生成(0,1,2),则编写一个散列{(0,):True,(1,):True,(0,1):True,(0,2):True,(0,1,2):True}的方法,依此类推。然后你可以在这个哈希表中查找,看看你是否想要新的集合。这很好用。非常感谢你的帮助!您的解决方案和@user2357112的结果相同,但有趣的是,顺序不同。我用
line\u profiler
做了一些快速测试,您的解决方案大致相同。仅供参考,您的函数需要切片对象,而不仅仅是
iterable
参数中的任何
iterable
。这非常有效。非常感谢你的帮助!正如我在对@hgwell's的评论中提到的,您的解决方案和@hgwell's产生相同的结果,但有趣的是,顺序不同。我用
line\u profiler
做了一些快速测试,您的解决方案在速度方面大致相同。也非常感谢vocab帮助(前缀)。
def nonprefix_combinations(iterable, maxlen):
    iterable = list(iterable)
    if not (iterable and maxlen):
        return
    for comb in combinations(iterable, maxlen):
        yield comb
    for length in xrange(maxlen-2, -1, -1):
        for comb in combinations(iterable[:-1], length):
            yield comb + (iterable[-1],)