【问题标题】:How can I obtain all combinations of my list?如何获得我的列表的所有组合?
【发布时间】:2021-10-20 22:52:38
【问题描述】:

我正在尝试创建一个包含两个数字的所有可能组合的数组。

我的数组是[0, 17.1]

我希望在一个包含 48 个元素的列表中获得这两个值的所有可能组合,这两个元素都可以重复。

from itertools import combinations_with_replacement
array = [0, 17.1]
combo_wr = combinations_with_replacement(array, 48)
print(len(list(combo_wr)))

我试图利用 itertools.combinations_with_replacement 创建如下所示的内容 -> combo_wr = combinations_with_replacement(array, 48)

当我打印这个长度时,我希望得到一个更大的数字,但我只得到这些数字的 49 种组合。我哪里出错了,或者还有哪些其他功能可以更好地获得所有可能的组合,在实例中顺序并不重要。

以下是我迄今为止为可重复性所做的尝试

>>> from itertools import combinations_with_replacement
>>> array = [0, 17.1]
>>> combo_wr = combinations_with_replacement(array, 48)
>>> print(len(list(combo_wr)))
49

【问题讨论】:

  • combinations 认为顺序无关紧要,您会得到17.1 有多少元素的所有组合,从 0(它们都是 0)到 48(它们都是)所以有 49 个组合,做你想要permutationsproduct(array, repeat=48) 代替吗?
  • 如果它是 0 或 17.1 的所有 48 个位置组合的列表 - 实际上是 48 位,因此 2^48,大约 2.8 * 10^14 个元素,那么您的列表将会非常长。
  • 啊,你当然是对的。 OP 被这个数字弄糊涂了,我被这个数字弄糊涂了,这表明他们实际上是按照我的建议去做的,但我同意所使用的术语另有说明。
  • 您在这里真正想解决什么问题,需要这两个数字在 48 个位置上的所有排列?看来您在这里处理的是 XY 问题。
  • 最终,我试图找到一个最合适的时间,我可以运行泵来填充水库。我尝试了许多数值求解器,但我觉得他们并没有解决所有的可能性。我有许多限制条件,例如保持在最小和最大水平内,并以最便宜的成本交付最小数量。所以这就是为什么我正在寻找所有可能满足当时要求的解决方案。

标签: python arrays itertools


【解决方案1】:

48 数字序列分别从 2 个不同的选项中选择,给出了 2^48 的搜索空间,即 281.4 万亿。

一个附加的约束,数字的总和应该大于 250,然后 [0,17.1] 意味着至少 15 个元素必须是 17.1,因此您将搜索空间减少了 48 choose 15,即 1 万亿, IE不足以产生太大影响。

如果您将第一个(或最后一个)15 个元素设置为 17.1,那么它将减少搜索空间以选择其余元素,因此 2^(58-15) = 2^33 是 86 亿,但我不确定这是约束你真的想要,或者它仍然足够小而有用。

因此,产生您要求的结果的代码不太可能对您有所帮助。

但如果你仍然想要帮助生成数以万亿计的组合

澄清可供您使用的不同选项:

  • itertools.product 给出了所有可能的正面和反面序列
  • itertools.combinations 给出给定长度的无序子集
  • itertools.permutations 提供了对给定序列重新排序或对给定长度的所有子集进行排序的所有方法
  • itertools.combinations_with_replacement 给出了不同选项的重复次数是唯一的所有子集,对于 2 个元素输入,这就像“在 n 个硬币翻转之后,正面的数量是唯一的序列是什么”

permutationscombinationslen(array)==2r=48 没有意义,因为它们是关于子集的,product 会比你想要的更多的冗余。

在实例中顺序无关紧要。

如果是这种情况,那么您可能只是期待更多的组合。

我希望得到所有这些,但是否可以缩小那些满足总和值 >= 250 的范围

好的,那么您可以使用combinations_with_replacements 获取元素总和的每个唯一值,然后在上面执行permutations

array = [0, 17.1]
reps = 48
lower_bound = 250
upper_bound = float("inf") # you might have an upper bound, if not you can remove this from the condition below or leave it as inf
for combo in combinations_with_replacement(array, reps):
    if lower_bound <= sum(combo) <= upper_bound:
        # this combo of 'number of elements that are 17.1` meets criteria for further investigation
        for perm in permutations(combo):
            do_thing(perm)

尽管这仍然会访问大量重复条目,因为具有大量重复条目的序列中的permutations 将交换相等的元素并给出相同的条目,因此我们可以做得更好。

首先,combinations_with_replacement 实际上只传达我们正在处理的每个元素的数量,因此我们只需执行 for k in range(reps) 即可获取该信息,然后希望每个排列恰好具有第二个元素的 k 重复在array - 这恰好相当于选择k 索引来设置。

所以我们可以使用combinations(range(reps), k) 来获取一组索引以设置为第二个元素,我相信这是您必须检查以满足“总和大于250 要求的最小可能序列集.

reps = 48
def isSummationValidCombo(summation):
    return summation >= 250

for k in range(reps):
    summation = array[1] *k + array[0] * (reps-k)
    if not isSummationValidCombo(summation):
        continue
    for indices_of_sequence_to_set_to_second_element in combinations(range(reps), k):
        # each combination of k inices to set to the higher value
        seq = [array[0]]*reps
        for idx in indices_of_sequence_to_set_to_second_element:
            seq[idx] = array[1]
        do_thing(seq)

这将使您的组合数量达到 280 万亿,而 product 将达到 281 万亿,因此您可能需要找出其他技术来减少搜索空间

【讨论】:

  • 请注意,从 OP 的 cmets 来看,很明显他们说错了,实际上是在排列之后 - 位置很重要。
  • 好的,现在它可能实际上有助于从 cmets 添加信息
  • 检查一个值是否小于或等于该类型可以表示的最大值似乎是多余的?这段代码忽略了它可能永远运行的事实,因为do_thing() 应该计算一些更严重的东西,由 OP 的 cmets - 所以虽然你在解释如何编码时似乎是正确的,但你在回避解决方案实际上不起作用的事实。
  • 该代码如何永远运行?两个循环都受它们可以迭代多少次重复的限制 - 或者你的意思是它会花费不合理的长时间?我总是忘记permutations 不能有效地处理重复条目,所以我添加了另一个版本来解决这个问题,尽管可能有更简单的方式来表示它。
  • “永远”,出于所有实际意图和目的,因为该程序将在任何人的一生中启动,并且永远不会看到完成。当然不合理,实际上它永远不会完成。您似乎忽略了 OP 添加的 cmets,从而阐明了他们需要此功能的应用程序类型。由于他们的问题受到限制,您最终会在非常大的搜索空间中寻找蛮力,而您建议的方法忽略了这一点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-10-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-15
相关资源
最近更新 更多