我想找到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] .......]
答案 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
- 正整数的数量我们可以使用。
然后,每个函数将以二维{的形式返回(给定target
和n
个数字)将生成该目标的所有组合 {1}}。
我们必须考虑的唯一特殊情况是"叶子节点"我们的递归树(我们有一个特定目标的情况,但list
,所以我们只有一个数字来制作目标)。这很容易处理,我们只需要记住,我们应该总是返回所有组成目标的组合,所以在这种情况下,只有一个"组合"其中是n == 1
。
然后(如果target
)其余部分是自解释的,我们只是循环遍历小于n > 1
的每个数字并添加target
个组合(list
)与再次调用该函数的结果。
但是,在我们将这些组合连接到cs
之前,我们需要使用list
将comprehension
(下一个数字)添加到每个组合的开头。
那就是它!希望您能看到上述内容如何转换为以下代码:
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
为target
而10
为n
以使其更清晰)显示其有效:
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
的情况。有一次,在4
和6
之后,将使用1
目标调用该函数。该算法将如我们已经解释的那样,并使用3
数字返回组合以生成2
。但是,如果我们现在考虑另一个案例,当要求函数提供使用6
和6
调用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]