【问题标题】:Python: powerset of a given set with generators [duplicate]Python:带有生成器的给定集合的幂集[重复]
【发布时间】:2013-09-20 12:25:20
【问题描述】:

我正在尝试使用 generators 在 Python 中构建给定集合的子集列表。说我有

set([1, 2, 3])

作为输入,我应该有

[set([1, 2, 3]), set([2, 3]), set([1, 3]), set([3]), set([1, 2]), set([2]), set([1]), set([])]

作为输出。我怎样才能做到这一点?

【问题讨论】:

  • 谷歌为:python itertools powerset recipe?这正是您要问的...然后在docs.python.org/2/library/itertools.html - 搜索powerset...
  • 这对我没有帮助,请查看下面的回复。
  • 好吧,既然输入是一个集合,那么输出不能包含重复的元素,所以一个元组没有任何可能性,如果你真的想把它转换回一个集合。此外,由于它返回chain.from_iterable,因此您实际上拥有了一个生成器。有什么是您无法轻松适应您的要求的? return imap(set, chain.from_iterable(...)) ?

标签: python algorithm set generator powerset


【解决方案1】:

最快的方法是使用 itertools,尤其是链和组合:

>>> from itertools import chain, combinations
>>> i = set([1, 2, 3])
>>> for z in chain.from_iterable(combinations(i, r) for r in range(len(i)+1)):
    print z 
()
(1,)
(2,)
(3,)
(1, 2)
(1, 3)
(2, 3)
(1, 2, 3)
>>> 

如果您需要生成器,只需使用 yield 并将元组转换为集合:

def powerset_generator(i):
    for subset in chain.from_iterable(combinations(i, r) for r in range(len(i)+1)):
        yield set(subset)

然后简单地说:

>>> for i in powerset_generator(i):
    print i


set([])
set([1])
set([2])
set([3])
set([1, 2])
set([1, 3])
set([2, 3])
set([1, 2, 3])
>>> 

【讨论】:

  • 我需要为此构建一个生成器,一个生成所需子集的函数。此外,生成器必须包含集合,而不是元组。
  • @Pawelmhm 或根据我对 OP 的评论 - 只需将其包装在 imap(set, ...) 中并保持功能完全相同...
【解决方案2】:

来自 itertools 文档的 recipes 部分:

def powerset(iterable):
    s = list(iterable)
    return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))

【讨论】:

  • 我需要为此构建一个生成器,一个生成所需子集的函数。此外,生成器必须包含集合,而不是元组。
【解决方案3】:

我知道这太老了,但我一直在寻找相同问题的答案,经过几个小时的网络搜索不成功,我想出了自己的解决方案。这是代码:

def combinations(iterable, r):
    # combinations('ABCDE', 3) --> ABC ABD ABE ACD ACE ADE BCD BCE BDE CDE
    pool = tuple(iterable)  # allows a string to be transformed to a tuple
    n = len(pool)  
    if r > n:  # If we don't have enough items to combine, return None
        return
    indices = range(r)  # Make a set of the indices with length (r)
    yield [pool[i] for i in indices]   Yield first list of indices [0 to (r-1)]
    while True:
        for i in reversed(range(r)):  # Check from right to left if the index is at its
                                      # max value. If everyone is maxed out, then finish
            if indices[i] != i + n - r:  # indices[2] != 2 + 5 - 3
                break                    # 2 != 4  (Y) then break and avoid the return
        else:
            return
        indices[i] += 1  # indices[2] = 2 + 1 = 3
        for j in range(i + 1, r):  # for j in []  # Do nothing in this case
            indices[j] = indices[j - 1] + 1  # If necessary, reset indices to the right of
                                             # indices[i] to the minimum value possible.
                                             # This depends on the current indices[i]
        yield [pool[i] for i in indices]  # [0, 1, 3]


def all_subsets(test):
    out = []
    for i in xrange(len(test)):
        out += [[test[i]]]
    for i in xrange(2, len(test) + 1):
        out += [x for x in combinations(test, i)]
    return out

我从 itertools doc itertools.combinations 中获取了组合示例代码,并将其修改为生成列表而不是元组。当我试图弄清楚它是如何工作的(以便以后修改它)时,我做了注释,所以我会把它们放在那里,以防万一有人发现它们有帮助。最后,我创建了 all_substes 函数来查找长度为 1 到 r 的每个子集(不包括空列表,因此如果您需要它,只需从 out = [[]]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-09-02
    • 2021-03-01
    • 1970-01-01
    • 2014-01-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多