我需要从具有以下约束的列表中获取所有可能的5种组合:
到目前为止,这是我的代码:
number = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]
comb = [c for c in itertools.product(number, repeat=5) if c[0] + c[1] + c[2] + c[3] + c[4] == 1]
for cb in comp:
print(cb)
似乎我没有得到所有可能的组合。例如,输出的第一行将是
(0.1, 0.1, 0.1, 0.1, 0.6)
但不包括以下任何内容
(0.6, 0.1, 0.1, 0.1, 0.1)
(0.1, 0.6, 0.1, 0.1, 0.1)
(0.1, 0.1, 0.6, 0.1, 0.1)
(0.1, 0.1, 0.1, 0.6, 0.1)
,依此类推。我还尝试了
的其他方法itertools.combinations_with_replacement
itertools.permutations
答案 0 :(得分:4)
itertools.product函数会输出所需的内容,问题在于检查浮点数的相等性,为此您可以使用math.isclose:
city, state, zip, and house
答案 1 :(得分:2)
这似乎是一个有趣的情况,导致浮点算术错误导致总和不正确。可以在python documentation.
中找到更多信息。这是发生的事的一个例子:
>>> 0.1 + 0.6 + 0.1 + 0.1 + 0.1 == 1
False
一种解决方案是检查总和是否在1的误差范围之内。
comb = [c for c in itertools.product(number, repeat=5) if abs(sum(c) - 1) <= .01]
或者,您也可以四舍五入并进行比较以解决问题,如下所示:
comb = [c for c in itertools.product(number, repeat=5) if round(sum(c), 2) == 1]
答案 2 :(得分:1)
正如其他答案正确指出的那样,问题在于浮点比较。十分之一没有有限的二进制表示形式,除非其中有五个。
由于您对一组非常特殊的数字感兴趣,因此可以将它们映射为整数,而不用使用round
,isclose
或abs
比较。这样,您可以使比较精确,然后将结果映射回所需的数字。
在这种情况下,您可以将所有内容乘以10得到整数。对于更复杂的情况,您可能需要其他因素,完全不同的转换函数,甚至可能需要查找表。
number = range(1, 10)
comb = (tuple(x / 10 for x in c) for c in itertools.product(number, repeat=5) if sum(c) == 10)
for cb in comp:
print(cb)
其他一些小改进:
sum
将元素加在一起,而不是手动将其写出。它将使添加更多元素变得更加容易。comb
作为生成器,而不是将其变成占用内存的列表。