【问题标题】:Sort combinations by sum of its elements in Python在 Python 中按元素的总和对组合进行排序
【发布时间】:2017-04-27 15:50:35
【问题描述】:

我在 Python 中有一个庞大的整数列表(1000000+ 个元素),但为了简单起见,我将通过一个示例来说明我需要什么。假设我有这个列表:

A = [1,2,3,4,100]

现在我想获取该列表的所有组合(大小为 3),因此我使用了 itertools。

combinations = itertools.combinations(A,3)

但我的问题是这将按字典顺序返回组合:

(1,2,3)
(1,2,4)
(1,2,100)
(1,3,4)

等等。

我想获得按其元素总和排序的组合。那将是:

(1,2,3) 和 6, (1,2,4) 之和为 7, (1,3,4) 之和为 8,

以此类推。

我怎样才能做到这一点?

【问题讨论】:

  • 我会给每个组合一个总和值并按该值作为键进行排序 [(1,2,3),6] - 沿着这些线
  • 你估计有多少组合?
  • 组合的数量会很大,因为列表中有超过一百万个元素
  • 你有足够的内存来存储这么多组合吗?我的猜测是它需要大约 1.2e10 千兆字节
  • 您似乎正在尝试对诸如背包问题之类的问题使用蛮力。如果您描述实际问题,可能有更好的方法来解决它

标签: python sorting combinations itertools


【解决方案1】:

有序组合太大而无法放入内存

1,000,000 个事物的组合数是 166,666,166,667,000,000。它太大而无法放入内存,太大而无法排序,而且太大而无法在合理的时间内循环。

有关惰性生成这些组合的方法,请参阅 Donald Knuth 关于组合算法的分册中的 "GENERATING ALL COMBINATIONS"

可以放入内存的有序组合

只要组合的数量合理,最直接的方法是直接按组合对它们进行排序:

>>> import itertools
>>> import pprint

>>> A = [1, 2, 3, 4, 100]
>>> combinations = sorted(itertools.combinations(A, 3), key=sum)
>>> pprint.pprint(combinations)
[(1, 2, 3),
 (1, 2, 4),
 (1, 3, 4),
 (2, 3, 4),
 (1, 2, 100),
 (1, 3, 100),
 (1, 4, 100),
 (2, 3, 100),
 (2, 4, 100),
 (3, 4, 100)]

该技术使用sum() 作为key-functionsorted()

连接两个世界

nCr 大于实际可枚举的值时,通过从列表A 中删除较大的元素直到总和足够大以包含这些值来减少问题是有意义的。

【讨论】:

    【解决方案2】:

    这里要考虑的关键是组合的数量真的很大~(1000000)^^3 因此,任何 O(NlogN) 的排序算法都会很糟糕。我们需要 O(N) 中的一些东西。

    我们可以尝试创建一个 SortedDictionary (sorteddict) 或使用标准的外部哈希实现(如 memcache)将组合存储为 {总和:[元组1,元组2]}。此操作的复杂度将是 ~O(N)

    然后,创建一个新列表,遍历缓存和所有值。同样,复杂度将是 O(N)。

    总的来说,我们将有 O(2N) 比 O(NLogN) 更有效。希望这会有所帮助!

    【讨论】:

    • 我没有遵循您的方法如何降低按值总和排序的时间复杂度...本质上,您创建了一个映射sum:List[tuples],然后再次对其进行迭代,但这如何按sum排序?我认为,任何维护排序顺序的有序字典实现都必须使用一些超过 O(N) 的插入操作,不是吗?
    • 我不确定您的陈述“我认为,任何维护排序顺序的有序字典实现都必须在有序列表上使用一些超过 O(N) 的插入操作”。我想有比在每次插入时进行排序更好的处理方法,比如将哈希键作为内存的索引或类似的东西。同意在某些情况下,我们可能需要做一些排序和复制——但这可以摊销。可能是让我们检查一下它是如何实现的并讨论一下。
    • 出于真正的好奇心,我只参加了几门粗略的 CS 课程,因为我的背景是生物学,所以我对基本算法/数据结构之外的知识深度相当有限。但基本上,我不确定您上面的方法如何提供 sorted 元组序列...
    • 如果元组和顺序得到保证,那么它只是遍历整个字典并生成新的组合列表。新的组合列表将按相同的顺序排列对吧?
    • 好吧,如果您使用collections.OrderedDict,那么此列表将按相同的顺序排列,但该顺序不会排序
    猜你喜欢
    • 2015-06-21
    • 1970-01-01
    • 2019-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-28
    • 1970-01-01
    相关资源
    最近更新 更多