Python - 如何将数字列表的所有组合相加以达到目标。使用号码是可选的

时间:2016-09-14 06:58:51

标签: python sum combinations permutation

我有一个数字列表

lis = [497.96, 10, 5084, 156.43, 381.3, 3298.85, 625.68]

我想以各种方式求和以达到8276的目标数。我还需要看看是否丢掉分数或舍入有助于达到目标。请注意,使用数字是可选的。

我试过

from itertools import combinations
lis = [497.96, 10, 5084, 156.43, 381.3, 3298.85, 625.68]
for i in xrange(1, len(lis) + 1):   #xrange will return the values 1,2,3,4 in this loop
    if sum(list(combinations(lis, i))) == 8276:
       print list(combinations(lis, i))

但是这给了我

TypeError: unsupported operand type(s) for +: 'int' and 'tuple'

我不确定为什么或如何修复。

3 个答案:

答案 0 :(得分:3)

您尝试将所有组合与给定长度相加,而不是计算单个组合的总和。相反,你应该循环组合并检查每个组合的总和:

$

特定错误的原因是sum采用可选参数from itertools import combinations lis = [497.96, 10, 5084, 156.43, 381.3, 3298.85, 625.68] for i in xrange(1, len(lis) + 1): for comb in combinations(lis, i): if sum(comb) == 8276: print comb 这是默认值。如果未提供参数,则默认为start。基本上您的原始代码正在尝试执行以下操作:

0

答案 1 :(得分:1)

你提到:

  

我还需要看看丢掉美分或舍入是否有助于达到目标。

..下面的代码将显示最接近的n组合,以及它们对目标数字的绝对差异。

适用于python3python2

from itertools import combinations
# set the number of closest combinations to show, the targeted number and the list
show = 5
target = 8276
lis = [497.96, 10, 5084, 156.43, 381.3, 3298.85, 625.68]

diffs = []
for n in range(1, len(lis)+1):
    numbers = combinations(lis, n)
    # list the combinations and their absolute difference to target
    for combi in numbers:
        diffs.append([combi, abs(target - sum(combi))])

diffs.sort(key=lambda x: x[1])

for item in diffs[:show]:
    print(item[0], round(item[1],10))

输出将显示前n个最接近的组合(与目标数字的组合/绝对差异):

(5084, 3298.85) 106.85
(10, 5084, 3298.85) 116.85
(5084, 156.43, 3298.85) 263.28
(10, 5084, 156.43, 3298.85) 273.28
(5084, 381.3, 3298.85) 488.15

这表明您可以获得的距离最近为(5084, 3298.85),显示的差异为106.85

注意

见btw Note on floating point calculation

修改

对于它的运动,上述脚本的缩写版本:

from itertools import combinations 
# set the number of closest combinations to show, the targeted number and the list
show = 5
target = 8276
lis = [497.96, 10, 5084, 156.43, 381.3, 3298.85, 625.68]

diffs = [item for sublist in [[
    [combi, abs(target - sum(combi))] for combi in combinations(lis, n)
     ] for n in range(1, len(lis)+1)] for item in sublist]

diffs.sort(key=lambda x: x[1])
[print(item[0], round(item[1],10)) for item in diffs[:show]]

答案 2 :(得分:0)

如果您想考虑可以丢弃美分的情况,或者您可以舍入到最接近的整数,这是一个解决方案。这个要求将一个简单的解决方案变成了一个非常复杂为了解释上述要求,我扩展了每个数字以包括其他可能的情况。展开的列表显示了获取组合的新列表:

import math
import itertools as it
tolerance = 150
target_sum = 8392
found = False
lis = [497.96, 10, 5084, 156.43, 381.3, 3298.85, 625.68]

def add_throw_and_round(num):
    num_list = [num]
    if int(num) != float(num):
        num_list.append(math.floor(num))
    if round(num) not in num_list:
        num_list.append(round(num))
    return sorted(num_list)

lis_expanded = map(add_throw_and_round, lis)
print "Expanded list:\n", lis_expanded, "\n\nTarget sum:\n", target_sum, "\n"
for n in range(1,len(lis) + 1):  # n is number of summands in pick
    lis_combos = it.combinations(lis_expanded, n)
    for lis_combo_n in lis_combos:
        for combo_n in (it.product(*lis_combo_n)):
            sum_ = sum(combo_n)
            if sum_ == target_sum:
                found = True
                answer = combo_n
            if sum_ > target_sum - tolerance and sum_ < target_sum + tolerance:
                print "sum:", sum_, "\tCombination: ", combo_n
if found:
    print "\nThere is a match: ", answer
else:
    print "\nNo exact match found"

所以我决定显示目标总和的150以内的所有金额,只是为了看它是否有效。没有匹配,总和恰好是8276:

>>> 
===== RESTART: C:/Users/Joe/Desktop/scripts/Stack_overflow/cents_py2.py =====

Expanded list:
[[497.0, 497.96, 498.0], [10], [5084], [156.0, 156.43], [381.0, 381.3], [3298.0, 3298.85, 3299.0], [625.0, 625.68, 626.0]] 

Target sum:
8276 

sum: 8382.0     Combination:  (5084, 3298.0)
sum: 8382.85    Combination:  (5084, 3298.85)
sum: 8383.0     Combination:  (5084, 3299.0)
sum: 8392.0     Combination:  (10, 5084, 3298.0)
sum: 8392.85    Combination:  (10, 5084, 3298.85)
sum: 8393.0     Combination:  (10, 5084, 3299.0)

No exact match found
>>> 

请注意,它会测试美分被抛出和舍入的情况。 只是为了测试当目标总和匹配时是否会报告匹配,我尝试了target_sum = 8392,因为输出显示一个组合应该匹配它。所以这是这种情况下的输出:

>>> 
===== RESTART: C:/Users/Joe/Desktop/scripts/Stack_overflow/cents_py2.py =====
Expanded list:
[[497.0, 497.96, 498.0], [10], [5084], [156.0, 156.43], [381.0, 381.3], [3298.0, 3298.85, 3299.0], [625.0, 625.68, 626.0]] 

Target sum:
8392 

sum: 8382.0     Combination:  (5084, 3298.0)
sum: 8382.85    Combination:  (5084, 3298.85)
sum: 8383.0     Combination:  (5084, 3299.0)
sum: 8392.0     Combination:  (10, 5084, 3298.0)
sum: 8392.85    Combination:  (10, 5084, 3298.85)
sum: 8393.0     Combination:  (10, 5084, 3299.0)
sum: 8538.0     Combination:  (5084, 156.0, 3298.0)
sum: 8538.85    Combination:  (5084, 156.0, 3298.85)
sum: 8539.0     Combination:  (5084, 156.0, 3299.0)
sum: 8538.43    Combination:  (5084, 156.43, 3298.0)
sum: 8539.28    Combination:  (5084, 156.43, 3298.85)
sum: 8539.43    Combination:  (5084, 156.43, 3299.0)

There is a match:  (10, 5084, 3298.0)
>>>