【问题标题】:How to generate all possible combinations of given length如何生成给定长度的所有可能组合
【发布时间】:2020-10-03 21:59:47
【问题描述】:

假设我们有一个价格列表items_prices = [1500, 2000, 1600, 2100, 2200, 1400, 1900]

我们希望找到将所有 7 个价格放入桶中的所有可能组合,每个桶中包含以下价格数量[3, 2, 2]。价格是否放在同一个桶内无关紧要,但放在哪个桶价格上却很重要。

如何做到这一点?我找到了this answer,但它假设我们只对给定元素的r 长度子序列的一种组合感兴趣。但是在这里,我们还对包含3 价格的第一个组合之后的剩余部分感兴趣,然后是2,最后是2

请注意,给定存储桶中的 7 个价格和组合是一般问题的简单案例。

【问题讨论】:

  • 你能提供你期望的输出吗?
  • 请举几个例子来说明什么在定价中重要,什么不重要。
  • 单独的存储桶有什么不同吗?我看不出ABCDEFG 和三个独立的桶ABCDEFG 之间有什么区别。
  • 我们的目标是最大限度地讨价还价。假设我们在桶中的项目越多,我们在一个桶中最便宜的项目获得的折扣就越多。假设当桶中有 2 件商品时,我们获得 10% 的折扣,当桶中有 3 件商品时,我们获得 20% 的折扣,依此类推。然而,为了获得更高的价格,将物品分成几个桶而不是全部购买可能是值得的。
  • 不清楚 3/2/2 内的项目顺序是否重要。如果顺序确实很重要,那么@YossiLevi 的解决方案就可以了。如果顺序无关紧要,那么您需要使用 itertools.combinations 拉出三个元素,然后使用嵌套的 itertools.combinations 处理其他四个元素。

标签: python python-3.x combinations


【解决方案1】:

我可能对此解释有误,如果有,我会编辑此答案,但我假设单个组中的顺序无关紧要。

如果是这样,则有 7C5 = 21 种唯一方式(例如,在 3 组中,[1500, 2000, 1600][2000, 1600, 1500] 相同)。我只是简单地做所有独特的组合(不是排列),从 7 中选择 5 个价格,然后将该 5 拆分为 3 和 2,然后附加未选择的剩余 2 个值作为第三组(按任意顺序)。

他们是:

((1600, 1400, 1900), (2000, 2100), (2200, 1500))
((1600, 1400, 1900), (2000, 2200), (1500, 2100))
((1600, 1400, 1900), (2000, 1500), (2200, 2100))
((1600, 1400, 1900), (2100, 2200), (2000, 1500))
((1600, 1400, 1900), (2100, 1500), (2000, 2200))
((1600, 1400, 1900), (2200, 1500), (2000, 2100))
((1600, 1400, 2000), (2100, 2200), (1500, 1900))
((1600, 1400, 2000), (2100, 1500), (2200, 1900))
((1600, 1400, 2000), (2200, 1500), (1900, 2100))
((1600, 1400, 2100), (2200, 1500), (2000, 1900))
((1600, 1900, 2000), (2100, 2200), (1400, 1500))
((1600, 1900, 2000), (2100, 1500), (1400, 2200))
((1600, 1900, 2000), (2200, 1500), (1400, 2100))
((1600, 1900, 2100), (2200, 1500), (1400, 2000))
((1600, 2000, 2100), (2200, 1500), (1400, 1900))
((1400, 1900, 2000), (2100, 2200), (1600, 1500))
((1400, 1900, 2000), (2100, 1500), (1600, 2200))
((1400, 1900, 2000), (2200, 1500), (1600, 2100))
((1400, 1900, 2100), (2200, 1500), (1600, 2000))
((1400, 2000, 2100), (2200, 1500), (1600, 1900))
((1900, 2000, 2100), (2200, 1500), (1600, 1400))

计算自

[(chosen_5[:3], chosen_5[3:5], tuple(set(items_prices) - set(chosen_5))) for chosen_5 in tuple(itertools.combinations(items_prices, 5))]

请注意,在所有 3 个元组中,实际值并不完全相同,即使顺序不同,因为我们不关心值的顺序 - 我们可以将每个顺序中的 3 个元组视为 3 (冻结)集。


但是,如果您的意思是各个组中的顺序确实很重要,那么有 7 个! = 5040 个可能的排列,这与选择 7 个中的任何 1 个然后之后,6 个 remaning 中的任何 1 个(因为您已经选择了一个)然后 5 个中的 1 个......直到最后 1. 它们都可以使用

[(this_permutation[:3], this_permutation[3:5], this_permutation[5:]) for this_permutation in itertools.permutations(items_prices)]
((1500, 2000, 1600), (2100, 2200), (1400, 1900))
((1500, 2000, 1600), (2100, 2200), (1900, 1400))
((1500, 2000, 1600), (2100, 1400), (2200, 1900))
((1500, 2000, 1600), (2100, 1400), (1900, 2200))
((1500, 2000, 1600), (2100, 1900), (2200, 1400))
((1500, 2000, 1600), (2100, 1900), (1400, 2200))
((1500, 2000, 1600), (2200, 2100), (1400, 1900))
((1500, 2000, 1600), (2200, 2100), (1900, 1400))
((1500, 2000, 1600), (2200, 1400), (2100, 1900))
((1500, 2000, 1600), (2200, 1400), (1900, 2100))
((1500, 2000, 1600), (2200, 1900), (2100, 1400))
((1500, 2000, 1600), (2200, 1900), (1400, 2100))
...

请注意,第一个和第二个元组是不同的,因为 2200 和 1500 的顺序不同,使用 combinations 而不是 permutations 在其他输出中不会区分

【讨论】:

  • 答案的第一部分是我一直在寻找的东西。我们不关心单个存储桶(元组内部)中的顺序。伟大的一个班轮。
【解决方案2】:

首先,您发布的答案不假设任何内容。 “组合”是一个定义明确的术语。见https://mathworld.wolfram.com/Combination.html

其次,我将按如下方式处理问题(在伪代码中):

  • 生成从0len(items_prices) - 1的所有索引列表
  • 根据给定索引生成长度为 3 的所有组合的列表(使用组合的正式定义和您链接的 itertools.combinations 函数)。
  • 对于每个生成的组合:
    • 删除选定的索引
    • 从剩余的索引列表中为下一个存储桶(在您的示例中长度为 2)生成组合

只要你没有水桶就继续。

我使用索引而不是元素来处理输入时价格可能重复的情况。如果您有不同的约束条件,您可以使用实际值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-01-04
    • 1970-01-01
    • 1970-01-01
    • 2021-12-14
    • 1970-01-01
    • 2012-02-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多