找到最接近给定数字python的所有数字

时间:2018-02-07 03:41:19

标签: python python-2.7 subset-sum

我在下面有一个脚本,它给出了给定总和最接近的2个值。它还迭代给定总和的列表,并在每次迭代后删除已经使用过的数字。

我需要修改此脚本,使其生成最接近每个总和的必要数量的值,而不是2.脚本需要接受浮点值并且不能重用值。实际上,它需要选择最接近目标的最有效集合,更新集合以移除使用的值,然后继续下一个目标等。

对于成对它,对于需要3个数字或4个等实际最接近总和的特定用例/集合,它不能很好地工作。我需要这个脚本也能够接受这个脚本当前所做的浮点值。

我们非常感谢任何建议。如果有人知道更好的脚本,请告诉我。

import sys
def find_closese_sum(numbers, target):
    start = 0
    end = len(numbers) - 1
    result = sys.maxint
    result_tuple = None
    while start < end:
        if numbers[start] + numbers[end] == target:
            print 0, (numbers[start], numbers[end])
            return
        elif numbers[start] + numbers[end] > target:
            if abs(numbers[start] + numbers[end] - target) < result:
                result = abs(numbers[start] + numbers[end] - target)
                result_tuple = (numbers[start], numbers[end])
            end -= 1
        else:
            if abs(numbers[start] + numbers[end] - target) < result:
                result = abs(numbers[start] + numbers[end] - target)
                result_tuple = (numbers[start], numbers[end])
            start += 1

    for i in result_tuple:
        numbers.remove(i)

    return result_tuple

if __name__ == "__main__":
    target = [14,27,39]
    numbers = [1,5,5,10,7,8,11,13,66,34]
    print numbers
    numbers = sorted(numbers)


    for i in target:
        result_shown = find_closese_sum(numbers, i)

        print result_shown

4 个答案:

答案 0 :(得分:0)

我没有看到任何优雅的方式来做到这一点,所以你可能不得不暴力解决方案。制作所有可能的数字子集,求和,并检查哪个最接近目标。它看起来像这样。

from itertools import permutations

def find_closest_sum(numbers, target, n):
    permlist = list(permutations(numbers, n))
    sumlist = [sum(l) for l in permlist]
    maxpos = 0
    for i in range(1, len(sumlist)):
        if abs(sumlist[i] - target) < abs(sumlist[maxpos]-target):
             maxpos = i

     return permlist[maxpos]

numbers = [1,5,5,10,7,8,11,13,66,34]
result_shown = find_closest_sum(numbers, 20, 4)
print result_shown

使用排列会使您编写的大量代码变得不必要。

答案 1 :(得分:0)

我的回答是,使用python 3但你应该能够轻松移植它。

from itertools import combinations as c

if __name__ == "__main__":
    target = [14,27,39]
    numbers = [1,5,5,10,7,8,11,13,66,34]

    for combo in range(1,4):
        for i in target:
            #lambda to find the difference between sum and target
            diff = lambda x: abs(sum(x) - i)
            #get all unique combinations
            combos = {tuple(sorted(c)) for c in c(numbers, combo)}
            #sort them
            combos = sorted(combos, key = diff)
            #get the smallest difference
            smallest = diff(combos[0])
            #filter out combos larger than the smaller difference
            result = [c for c in combos if diff(c) == smallest]
            print('results for {}, best combinations are off by {}:'.format(i, smallest))
            print(result)

您说您需要排除用于之前结果的数字。要做到这一点,只需从列表中删除它们:

            #after print(result), inside the "for i in target" loop
            #if you want to exclude all numbers used in all combinations
            numbers = [n for n in numbers if n not in [b for a in result for b in a]]
            #if you only need to remove the first match
            numbers = [n for n in numbers if n not in result[0]]

答案 2 :(得分:0)

import numpy as np
import itertools

def find_closese_sum(numbers, targets):
    numbers = numbers[:]
    for t in targets:
        if not numbers:
            break
        combs = sum([list(itertools.combinations(numbers, r))
                     for r in range(1, len(numbers)+1)], [])
        sums = np.asarray(list(map(sum, combs)))
        bestcomb = combs[np.argmin(np.abs(np.asarray(sums) - t))]
        numbers = list(set(numbers).difference(bestcomb))
        print("Target: {},  combination: {}".format(t, bestcomb))

实施例

In [101]: import numpy as np
     ...: import itertools
     ...: 
     ...: def find_closese_sum(numbers, targets):
     ...:     numbers = numbers[:]
     ...:     for t in targets:
     ...:         if not numbers:
     ...:             break
     ...:         combs = sum([list(itertools.combinations(numbers, r))
     ...:                      for r in range(1, len(numbers)+1)], [])
     ...:         sums = np.asarray(list(map(sum, combs)))
     ...:         bestcomb = combs[np.argmin(np.abs(np.asarray(sums) - t))]
     ...:         numbers = list(set(numbers).difference(bestcomb))
     ...:         print("Target: {},  combination: {}".format(t, bestcomb))
     ...: 
     ...: targets = [14,27.,39]
     ...: numbers = [1.0,5,5,10,7,8,11,13,66,34]
     ...: find_closese_sum(numbers, targets)
     ...: 
Target: 14,  combination: (1.0, 13)
Target: 27.0,  combination: (5, 5, 10, 7)
Target: 39,  combination: (8, 34)

答案 3 :(得分:-1)

不要让它变得复杂,这是我的方法,试试这个:

import itertools
def finding_closet(ls,target,depth):
    closest = []
    for i in itertools.combinations(ls, depth):

        if sum(i) == target:
            return i
        else:
            closest.append((abs(sum(i) - target), i))
    return min(closest)[1]

Test_case 0:

print(finding_closet([1,5,5,10,7,8,11,13,66,34],20,2))

输出:

(7, 13)

Test_case 1:

print(finding_closet([1,5,5,10,7,8,11,13,66,34],20,4))

输出:

(1, 5, 5, 8)

test_case_3:

print(finding_closet([1,5,5,10,7,8,11,13,66,34],20,8))

输出:

(1, 5, 5, 10, 7, 8, 11, 13)