【问题标题】:Python combinations without repetitions没有重复的Python组合
【发布时间】:2016-04-05 14:38:14
【问题描述】:

我有一个数字列表,我想从中进行组合。如果我有清单:

t = [2,2,2,2,4]
c = list(itertools.combinations(t, 4))

结果是:

(2, 2, 2, 2)
(2, 2, 2, 4)
(2, 2, 2, 4)
(2, 2, 2, 4)
(2, 2, 2, 4)

但我想得到:

(2, 2, 2, 2)
(2, 2, 2, 4)

除了制作新列表和遍历第一个列表之外,是否可以消除重复?

【问题讨论】:

    标签: python


    【解决方案1】:

    由于大金刚指向集合,您可以通过将列表转换为集合来获取列表中的唯一值:

    t = [2,2,2,2,4]
    c = list(itertools.combinations(t, 4))
    unq = set(c)
    print(unq)
    

    结果将是:

    {(2, 2, 2, 4), (2, 2, 2, 2)}
    

    如果您想将其用作列表,可以通过以下方式将其转换回来:

    result = list(unq)
    

    另一种更干净、更全面的方式将是:

    t = [2,2,2,2,4]
    c = set(itertools.combinations(t, 4))
    

    【讨论】:

    • set(itertools.combinations(t, 4))
    • 是的,这将是干净的方式。
    • 不要那样做。为什么他要先投射到一个列表,然后再投射到一个集合,然后再回到一个列表?
    • @Randhawa..您的答案也应该提供 clean fix 代码...:)
    • 投反对票。绝对没有必要保留创建列表 => 设置 => 列表的方法。如果错误/没有必要,“继续他的代码”没有任何价值。
    【解决方案2】:

    我知道这有点晚了,但我想补充一点。

    set(itertools.combinations(t, 4)) 在大多数情况下会做得很好,但它仍然会在内部迭代所有重复的组合,因此它的计算量可能很大。如果没有很多实际的独特组合,情况尤其如此。

    这个只迭代独特的组合:

    from itertools import chain, repeat, count, islice
    from collections import Counter
    
    
    def repeat_chain(values, counts):
        return chain.from_iterable(map(repeat, values, counts))
    
    
    def unique_combinations_from_value_counts(values, counts, r):
        n = len(counts)
        indices = list(islice(repeat_chain(count(), counts), r))
        if len(indices) < r:
            return
        while True:
            yield tuple(values[i] for i in indices)
            for i, j in zip(reversed(range(r)), repeat_chain(reversed(range(n)), reversed(counts))):
                if indices[i] != j:
                    break
            else:
                return
            j = indices[i] + 1
            for i, j in zip(range(i, r), repeat_chain(count(j), counts[j:])):
                indices[i] = j
    
    
    def unique_combinations(iterable, r):
        values, counts = zip(*Counter(iterable).items())
        return unique_combinations_from_value_counts(values, counts, r)
    

    用法:

    >>> list(unique_combinations([2, 2, 2, 2, 4], 4)) # elements must be hashable
    [(2, 2, 2, 2), (2, 2, 2, 4)]
    
    # You can pass values and counts separately. For this usage, values don't need to be hashable
    # Say you have ['a','b','b','c','c','c'], then since there is 1 of 'a', 2 of 'b', and 3 of 'c', you can do as follows:
    >>> list(unique_combinations_from_value_counts(['a', 'b', 'c'], [1, 2, 3], 3))
    [('a', 'b', 'b'), ('a', 'b', 'c'), ('a', 'c', 'c'), ('b', 'b', 'c'), ('b', 'c', 'c'), ('c', 'c', 'c')]
    
    # combinations_without_repetition() is a generator (and thus an iterator)
    # so you can iterate it
    >>> for comb in unique_combinations([2, 2, 2, 2, 4], 4):
    ...     print(sum(comb))
    ...
    8   # 2+2+2+2
    10  # 2+2+2+4
    

    注意itertools.combinations() 是用 C 实现的,这意味着在大多数情况下它比我的 python 脚本快得多。仅当重复组合多于唯一组合时,此代码才比 set(itertools.combinations()) 方法更好。

    【讨论】:

      【解决方案3】:

      从技术上讲,你得到的实际上并不是重复的,这只是itertools.combinations 的工作原理,如果你阅读了链接页面中的描述:

      itertools.combinations(iterable, r)

      从输入迭代中返回 r 个长度的元素子序列。

      组合按字典排序顺序发出。因此,如果输入的可迭代对象已排序,则组合元组将在 排序顺序。

      元素根据其位置而不是其价值被视为唯一。所以如果输入元素是唯一的,就不会有 在每个组合中重复值。

      演示:

      >>> import itertools as it
      >>> list(it.combinations([1,2,3,4,5], 4))
      [(1, 2, 3, 4), (1, 2, 3, 5), (1, 2, 4, 5), (1, 3, 4, 5), (2, 3, 4, 5)]
      

      因此,正如在上一个答案中发布的那样,set() 将为您提供所需的独特值:

      >>> set(it.combinations(t, 4))
      {(2, 2, 2, 4), (2, 2, 2, 2)}
      

      【讨论】:

      • 那么,实际上有没有一种方法可以基于价值而不是基于位置来进行组合,即如果列表是[0,1,2,2],则给出(0,1) (0,2), (1,2)
      • @铁拳。很好的解释。
      【解决方案4】:

      现在可以使用包 more-itertools 来完成此操作,从 8.7 版开始,该包有一个名为 distinct_combinations 的函数来实现此目的。

      >>> from itertools import combinations
      >>> t = [2,2,2,2,4]
      >>> set(combinations(t, 4))
      {(2, 2, 2, 2), (2, 2, 2, 4)}
      
      >>> from more_itertools import distinct_combinations
      >>> t = [2,2,2,2,4]
      >>> list(distinct_combinations(t,4))
      (2, 2, 2, 2), (2, 2, 2, 4)]
      

      据我所知,我的测试性能非常有限,类似于@hahho 写的function

      【讨论】:

        猜你喜欢
        • 2019-04-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-09-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多