Python循环或任何迭代来查找所有组合,以满足条件

时间:2018-02-10 10:18:24

标签: python loops combinations

我想找到n个数字的所有可能组合,以便在Python中总和= 100

2个数字的样本:

x=[]
for i, j in itertools.product(range(0,101), range(0,101)):
    if i+j==100:
       x.append([i,j])

使用可变数量的迭代变量执行此操作的任何替代和巧妙方法,并以此形式获得结果: N = 5:

[[10,10,10,30,40], [100,0,0,0,0], [1,1,2,3,97] .......]

3 个答案:

答案 0 :(得分:3)

+-----+-----+----------+ | word|value| timestamp| +-----+-----+----------+ |hello| 1|1516364348| |hello| 2|1516364263| |hello| 3|1516365083| +-----+-----+----------+ 使用itertools.product参数,您可以使用repeat repeat迭代器range(1, 101)次数来repeat。这样您就不需要多次指定迭代器或生成所需数量的参数。例如,5次:

[i for i in itertools.product(range(1, 101), repeat=5) if sum(i) == 100]

答案 1 :(得分:3)

纯Python解决方案(即没有itertools.product

这里的主要困难是在函数内执行可变数量的for-loops。我们可以轻松解决这个问题的方法是使用 recursion ,它涉及一个调用自身的函数。

如果我们使用递归,那么在函数的任何实例中,实际上只迭代了一个for-loop。因此,要将此应用于手头的问题,我们希望我们的函数采用两个参数:我们尝试求和的数字的目标,以及n - 正整数的数量我们可以使用。

然后,每个函数将以二维{的形式返回(给定targetn个数字)将生成该目标的所有组合 {1}}。

我们必须考虑的唯一特殊情况是"叶子节点"我们的递归树(我们有一个特定目标的情况,但list,所以我们只有一个数字来制作目标)。这很容易处理,我们只需要记住,我们应该总是返回所有组成目标的组合,所以在这种情况下,只有一个"组合"其中n == 1

然后(如果target)其余部分是自解释的,我们只是循环遍历小于n > 1的每个数字并添加target个组合(list)与再次调用该函数的结果。

但是,在我们将这些组合连接到cs之前,我们需要使用listcomprehension(下一个数字)添加到每个组合的开头。

那就是它!希望您能看到上述内容如何转换为以下代码:

i

并且测试(def combos(target, n): if n == 1: return [[target]] cs = [] for i in range(0, target+1): cs += [[i]+c for c in combos(target-i, n-1)] return cs target10n以使其更清晰)显示其有效:

3

提高效果

如果我们考虑使用>>> combos(10, 3) [[0, 0, 10], [0, 1, 9], [0, 2, 8], [0, 3, 7], [0, 4, 6], [0, 5, 5], [0, 6, 4], [0, 7, 3], [0, 8, 2], [0, 9, 1], [0, 10, 0], [1, 0, 9], [1, 1, 8], [1, 2, 7], [1, 3, 6], [1, 4, 5], [1, 5, 4], [1, 6, 3], [1, 7, 2], [1, 8, 1], [1, 9, 0], [2, 0, 8], [2, 1, 7], [2, 2, 6], [2, 3, 5], [2, 4, 4], [2, 5, 3], [2, 6, 2], [2, 7, 1], [2, 8, 0], [3, 0, 7], [3, 1, 6], [3, 2, 5], [3, 3, 4], [3, 4, 3], [3, 5, 2], [3, 6, 1], [3, 7, 0], [4, 0, 6], [4, 1, 5], [4, 2, 4], [4, 3, 3], [4, 4, 2], [4, 5, 1], [4, 6, 0], [5, 0, 5], [5, 1, 4], [5, 2, 3], [5, 3, 2], [5, 4, 1], [5, 5, 0], [6, 0, 4], [6, 1, 3], [6, 2, 2], [6, 3, 1], [6, 4, 0], [7, 0, 3], [7, 1, 2], [7, 2, 1], [7, 3, 0], [8, 0, 2], [8, 1, 1], [8, 2, 0], [9, 0, 1], [9, 1, 0], [10, 0, 0]] 编号10的情况。有一次,在46之后,将使用1目标调用该函数。该算法将如我们已经解释的那样,并使用3数字返回组合以生成2。但是,如果我们现在考虑另一个案例,当要求函数提供使用66调用2(与以前相同)的组合时。请注意,即使我们将得到正确的答案(通过我们的递归2),我们将返回与之前相同的组合 - 当我们使用for-loop调用时1。此外,这种情况会经常发生:函数将从不同的情况调用,但要求给出之前已在不同时间计算过的相同组合。

这让位于一个名为memoization的优秀技术,它基本上只是意味着在返回之前将我们的函数结果存储为字典(3)中的key: value对。

然后我们只检查每个函数调用的开始,如果我们曾经使用相同的参数调用过(通过查看键是否在字典中),如果是,那么我们可以返回我们得到的结果上一次。

这大大加快了算法的速度。

mem

答案 2 :(得分:2)

这是对算法的简单泛化/部分优化。

使用repeat

修改@heemayl's alternative优于此解决方案。

import itertools

n = 3
x = []

x = [list(i) for i in itertools.product(*(range(0,101) \
             for _ in range(n))) if sum(i) == 100]