【问题标题】:Find combination of numbers from set that equal a given sum - Python从集合中查找等于给定总和的数字组合 - Python
【发布时间】:2017-10-25 05:57:01
【问题描述】:

编辑: 我知道这个问题已经被问了一百万次,但我似乎找不到任何适合我的特定场景的东西。出于上下文目的,我在 Windows 操作系统上运行 Python 3.6。

我试过以下代码:

def subset_sum(numbers, target, partial=[]):
    s = sum(partial)

    # check if the partial sum is equals to target
    if s == target:
        print(f"sum({partial})={target}")
        #print("sum({})={}".format(partial, target))
    if s == target:
        return  # if we reach the number why bother to continue

    for i in range(len(numbers)):
        n = numbers[i]
        #remaining = numbers[:i] + numbers[i+1:]
        remaining = numbers[i+1:]
        subset_sum(remaining, target, partial + [n])

s= [-765143.910000006, -14522903.45, -185360.52, -161161.559999994, -31947.78, 167450, 47715.46, -1725.24, -1532.91, 338381.23, -40962.19, -321.869999999997, -28215.17, -66345.71, 13063.28, -389.37, 6215992.30000001, 2193804.53000001, -458374.52, 106792.609999979, -335194.01, 203687.94, 91147.0500000003, -18.9500000000004, -19.1200000000016, -2.31494823310641]

k= [-2191.62999999806, 5481451.91, -17941.98, 166.719999999996, -2.72848410531878, -3.42659234320308, -13109322.84, -5320290.35000001, -977974.9, 2224562.69999999, 404360.300000002, 579934.88, 1131275.75, 3889264.3, 3364573.99000001, 5225874.59, 2191.62999999806, 176248.27, 19925.25, 2090.84, 11461.32, 3457.83, 4655.76, -17929.46, 449.48, 2187.61, 3084.35, 176274, 48909.78, 55.43]

x= [14795.41, 6497.05, 324.6, 5589.19, 2224.45, 5571.92, 3575.24, 3041.33, 4658.22, 6244.92, 433.59, 2146.55, 1489, 28686.93, 205, 2267.76, 1532.91, -12539.19, 46221.03, 9959.25, 20175.14, 735, 9449, 26880, 426.12, 1355.18, 220.48, 695.88, -389.99, -1.12, -37.56]

v= [-1.96999999999248, 1.58761892521397, -2.1600499167107, -2791.41999999999, 606814.85, -19.1200000000016, -1.49999999999995, -54.3300000000086, 34608.19, -661601.97, 3149949.45, 32247.78, 350.64, 328574.84, 42461.52, 1273, 6635.21, 504, -3100.27, 9868.07, 148179.28, 29205.46, -206.65, -552]

y = [s+k+x+v]

if __name__ == "__main__":
    subset_sum(y, -765143.910000006)

【问题讨论】:

  • 将源代码第 5 行替换为 print("(sum(%s)=%s)" % (partial, target))
  • @L3viathan 这是 Python3,所以应该是 print("sum(%s)=%s" % (partial, target))
  • @PatrickHaugh 哦,我没有看到顶部的评论。
  • 第二个问题,你最好利用这个机会写一个单元测试! docs.python.org/3/library/unittest.html
  • y = [s+k+x+v] 是一个列表列表,您需要的是 y = s+k+x+v。要将其转换为 int,请使用 y = [int(x) for x in s+k+x+v]

标签: python python-3.x


【解决方案1】:

这一行

print(sum(%s)=%s) % (partial, target)

是错误的,因为您对非字符串的内容使用了字符串格式化模式。你可能想这样做

print("sum(%s)=%s" % (partial, target))

这仍然是旧语法,您更喜欢the new syntax

print("sum({})={}".format(partial, target))

【讨论】:

  • 由于 OP 使用的是 Python 3.6,因此他们可以使用 f-string 使其更现代、更紧凑(更快):print(f"sum({partial})={target}")
  • 哦,太好了,我不知道!
  • 谢谢,伙计们——成功了!不过,我确实有一个后续问题:似乎当我尝试在集合中包含负数时,脚本失败了。我如何能够在集合中包含负数也与集合中的正数和/或负数组合进行测试以等于某个总和?例如,如果我有 (10, -5, -9, 8, -2) 并且我想要等于 5 的组合,则其中一个解决方案将是 10、-5。谢谢!
  • 不应该 remaining 代替 numbers[:i] + numbers[i+1:] 吗?在我看来,您缺少组合。 partial 也可能只是一个 int,你不需要连接到一个列表,只需将总和的结果累加即可。
  • 结束条件 (if s >= target) 也不适合作为达到负目标的条件。特别是,第一个总和(partial = [],所以为 0)会以任何负目标终止您的算法。
【解决方案2】:

关于 SyntaxError:您以不正确的方式使用了格式。更多关于 PyFormat 网站的信息,快速解决方案:

print("sum(%s) =%s" % (partial, target)) 

【讨论】:

    【解决方案3】:

    您的代码不起作用,因为

    print(sum(%s)=%s) % (partial, target)
    

    应该是

    print "sum(%s)=%s" %(partial, target)
    

    此外,您需要在主声明之后缩进该行

    if __name__ == "__main__":
    subset_sum([3,9,8,4,5,7,10],15)
    

    应该是这个

    if __name__ == "__main__":
      subset_sum([3,9,8,4,5,7,10],15)
    

    您的代码也不能完全正常工作,因为 subset_sum([3,9,8,4,5,7,10,-9],1) 不返回结果,即使它应该返回 [10,-9] =1。

    此外,为了改进您的代码,我建议您使用 memoization 以避免在对大量数字执行此操作时多次计算同一子集。

    【讨论】:

    • 您好游侠,感谢您的意见!您知道我可以进行哪些更改以使脚本也可以使用负数(例如您上面提供的示例)?
    • 看起来你的逻辑现在正在运行。话虽如此,您必须将 y = [s+k+x+v] 更改为 y = s+k+x+v
    【解决方案4】:

    我相信这段代码有效:

    def subset_sum(numbers, target, partial=[]):
        s = sum(partial)
        if len(numbers) == 0:
            return
        elif s == target:
            print("sum({})={}".format(partial, target))
            return
        else:
            for i in range(len(numbers)):
                n = numbers[i]
                remaining = numbers[:i] + numbers[i+1:]
                subset_sum(remaining, target, partial + [n])
    
    y = [-15, 5, 10, -10, 3, 7, -4, -2]
    
    if __name__ == "__main__":
        subset_sum(y, 6)
    

    随着可能的combinations 数量的增加,它可能会非常缓慢,你可以用数学方法计算它并以天文数字的方式增长,所以你觉得它永远不会结束。

    注意我没有 Python 3.6,所以这里的格式仍然是老式的。

    编辑:另一个注意事项是您应该never use equality between floats,就像在您的终止条件中使用您建议的新输入一样。您可以查看this answer 以获取if isclose(s, target) 条件的灵感。

    【讨论】:

    • @KevinA626 你试图编辑我的问题来问你的问题,所以不能这样工作。改为添加评论。你的错误是y = int[s+k+x+v],它有2个错误:第一个[s+k+x+v]是一个列表,而不是一个列表;其次,这不是您在 Python 中转换为 int 的方式。请改用map(int, somelist),或[int(x) for x in somelist]
    • 抱歉!新手。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-04-06
    • 2014-05-26
    • 2015-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多