【问题标题】:Recursively running a for loop within a for loop (python)在 for 循环中递归运行 for 循环(python)
【发布时间】:2016-07-18 22:51:36
【问题描述】:

我是 python 新手,我想尝试用它来解决电视节目倒计时中的数字游戏。 (rules for those unfamiliar)。我用谷歌搜索,结果是this has been done before - 但我没有正确理解代码,然后想为什么不自己试一试。我已经搜索过,还有其他人在寻找递归解决方案,但我无法让他们为我的示例工作(抱歉,毕竟我对此很陌生)。

我要做的是获取一个数字列表,然后循环将操作应用于它们的对并用输出替换该对。这将递归地重复,直到我们找到我们正在寻找的数字,或者数字列表的大小减少到 1。

我的函数“single_move_generator”是一个生成元组的生成器,形式为 ((a,b,operation), answer, numbers left to use)。我想将元组的最后一部分作为新列表返回到函数中,但也要跟踪第一部分,因为它是我们如何实现答案的“历史”。目前我有以下内容:

target = 155
numbers_to_use = [6, 25, 3, 2]
for a in single_move_generator(numbers):
    if a[1] == target:
        print(a[0])
    for b in single_move_generator(a[2]):
        if b[1] == target:
                print(a[0],b[0])
                quit()
        for c in single_move_generator(b[2]):
                if c[1] == target:
                    print(a[0],b[0],c[0])
                    quit()

产生:

(25, 6, 'add') (3, 2, 'add') (31, 5, 'multiply')

但我希望能够给它一个更大的数字列表,并让它继续直到列表达到第一个大小。我怀疑我需要一个 while 循环 - 但这种尝试不起作用。它不会找到目标或跟踪移动历史。

numbers_available = numbers
while len(numbers_available) >1 and target not in numbers_available:

    for a in single_move_generator(numbers_available):
        if a[1] == target:
            print("Target Found", a)           
            break

    numbers_available = a[2]

numbers_available = a[2]

我觉得必须有一种 Python 的方式来做这件事,这比我做的要整洁得多 - 任何提示都将不胜感激。谢谢!

【问题讨论】:

  • 我没有在你的代码中找到任何递归。在另一个循环下循环称为“嵌套循环”。
  • 什么是递归?我可能误会了。我接受我发布的是一个嵌套循环,但我想永远继续这种嵌套(或者更确切地说,直到达到某个点,但不知道需要多少循环)
  • 那么回溯是给你的。谷歌它。

标签: python loops for-loop recursion


【解决方案1】:

基于您使用元组(i, j, operation) 的想法,我写了以下内容。这是一个递归解决方案,因为主函数会回调自身。

from itertools import combinations, product

def check_operation(i, j, operation):
    """
    Check whether 'i operation j' is permitted.
    """
    if operation == '/' and j == 0:
        return False
    elif operation == '/' and i%j != 0:
        return False
    # if not playing with negative values
    #elif operation == '-' and i-j < 0:
    #    return False
    else:
        return True

def countdown(target, numbers, trackback):
    if target in numbers:
        print trackback
    for possibility in product(combinations(numbers,2), ['+', '*', '/', '-']):
        new_numbers = [k for k in numbers] # copy list, use list.copy in python 3
        i, j = possibility[0][0], possibility[0][1]
        operation = possibility[1]
        new_numbers.remove(i)
        new_numbers.remove(j)
        if not check_operation(i, j, operation):
            continue
        new_numbers.append(eval('%i%s%i' % (i, operation, j)))
        countdown(target, new_numbers, trackback+[possibility])

countdown(155, [6, 25, 3, 2], [])

它仅在存在解决方案时才有效,因为它不打算尽可能接近解决方案。但是它会返回所有的解决方案,而不仅仅是一个。

【讨论】:

  • 谢谢! Itertools 看起来很有用,所以我会更多地阅读它。这是对我的代码的更清晰的重写,并为我如何更好地处理它提供了很好的思考。感谢输入:)
【解决方案2】:

根据您发布的内容,这应该适合您:

def solve(numbers, target):
  for op, res, nums in single_move_generator(numbers):
    if res == target:
      return [op]
    ops = solve(nums, target)
    if ops:
      return [op] + ops

print(*solve(numbers_to_use, target))

它应该等同于您发布的嵌套 for 循环。

res == target 时到达递归的底部。 Python 函数默认返回None,所以如果对solve 的递归调用返回了一个真值,那么它一定已经达到了目标。 ops 将包含最后一个操作,如果它是递归的底部。然后将其附加到启动递归调用的操作并返回到上层。因此该函数将返回顶层的所有操作。

【讨论】:

  • 这是对我遇到的问题的修复 - 谢谢!我没有意识到(或想检查)函数可以调用自己。感谢您的意见
  • @Steve 回答您上面的问题。这(一个调用自身的函数)就是通常理解为递归的东西,而 MASh 说他没有找到。
猜你喜欢
  • 1970-01-01
  • 2015-12-27
  • 1970-01-01
  • 1970-01-01
  • 2018-08-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多