【问题标题】:Recursive function returning None for no good reason递归函数无故返回 None
【发布时间】:2020-07-10 23:04:34
【问题描述】:

我的目标是编写一个函数,它接收整数列表 - ints - 和求和目标 - s - 并返回列表中前两个整数加起来为 s 的列表按照它们在列表中从左到右出现的顺序。我有函数 print 来控制每次迭代,一切看起来都很好,除了它总是返回None,我不知道怎么做。 我的代码:

def sum_pairs(ints, s, a=0, b=1):
    if a == len(ints)-1 or b > 666:
        return None
    if b < len(ints):
        print(s, a,b,[ints[a],ints[b]], ints[a] + ints[b])
        if ints[a] + ints[b] == s:
            x = ints[a]
            y = ints[b]
            print([x,y], type([x,y]), [x,y] is None)
            return [x, y]
        else: 
            sum_pairs(ints, s, a, b=b+1)
    else:
        sum_pairs(ints, s, a=a+1, b=a+2)

我什至在 return 语句之前的步骤中检查了 [x,y] 是否为 None 并且它总是返回 False 但不知何故该函数仍然返回 None。有人可以填我吗?我是递归新手,所以问题可能出在那儿。

【问题讨论】:

  • 您的函数在一半的情况下缺少return 语句。
  • 将 return 放在递归调用的前面:return sum_pairs(ints, s, a, b=b+1)return sum_pairs(ints, s, a=a+1, b=a+2)。此外,该算法更容易表述为迭代而非递归
  • 克劳斯有正确的答案。不相关,我强烈建议使用调试器。

标签: python list recursion return


【解决方案1】:

我将开始编写一个通用的combinations 函数,它可以生成指定大小的组合 -

def combinations(items, size):
  if size == 0:
    yield ()
  elif not items:
    return
  else:
    head, *tail = items
    for p in combinations(tail, size - 1):
      yield (head, *p)
    yield from combinations(tail, size)

我们依赖 Python 的生成器 懒惰地 生成输出。我们可以使用list 来获取所有结果 -

data = [ 1, 2, 3, 4, 5, 6, 7, 8 ]

list(combinations(data, 2))
# [ (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (1, 7), (1, 8), (2, 3),
#   (2, 4), (2, 5), (2, 6), (2, 7), (2, 8), (3, 4), (3, 5), (3, 6),
#   (3, 7), (3, 8), (4, 5), (4, 6), (4, 7), (4, 8), (5, 6), (5, 7),
#   (5, 8), (6, 7), (6, 8), (7, 8) ]

可以很方便的生成其他大小的组合,输入的iterable可以包含任意类型的元素-

list(combinations("abcd", 3)))
# [ ('a', 'b', 'c'), ('a', 'b', 'd'),
#   ('a', 'c', 'd'), ('b', 'c', 'd') ]

通过将combinations 编写为独立函数,我们解开了程序的关注点。因此sum_pairs 易于编写和测试。我们将2 作为size 参数传递,因为我们想要生成对(两个数字)-

def sum_pairs(ints, goal):
  for p in combinations(ints, 2): # <-- use combinations
    if sum(p) == goal:
      return p
  return None                     # <-- don't forget unsolvable case


print(sum_pairs(data, 13))
# (5, 8)

因为我们使用的是 Python 的生成器,所以sum_pairs 会在找到答案后立即返回。这种短路行为意味着不会浪费不必要的组合或迭代。

当给定一个无法达到的目标时,sum_pairs 将返回 None -

print(sum_pairs(data, 99))
# None

一个小的修改展示了我们的combinations 泛型的有效性。在这个程序中,any_sum 将找到总和达到我们预期目标的 任何 大小的组合 -

def any_sum(ints, goal):
  for size in range(len(ints)):
    for p in combinations(ints, size + 1):
      if sum(p) == goal:
        return p
  return None

虽然这不是 any_sum 的最有效实现,但它确实展示了如何在不引入新复杂性的情况下重用 combinations -

print(any_sum(data, 17))
# (2, 7, 8)

print(any_sum(data, 25))
# (4, 6, 7, 8)

print(any_sum(data, 33))
# (3, 4, 5, 6, 7, 8)

print(any_sum(data, 99))
# None

【讨论】:

    猜你喜欢
    • 2014-12-06
    • 1970-01-01
    • 2021-02-18
    • 2021-12-23
    • 1970-01-01
    • 2021-11-13
    相关资源
    最近更新 更多