简体   繁体   English

递归回溯-python。 不返回价值

[英]recursive backtracking - python. not returning value

Problem 问题

I am aware that somewhere in my function, I am not returning something I should. 我知道在函数的某个地方,我没有返回应有的东西。

I am returning the recursive call, but it appears that I am not returning "all the way out" 我正在返回递归调用,但似乎没有返回“全部”

Context 语境

I am doing a depth first search of every single combination in a list. 我正在对列表中的每个单个组合进行深度优先搜索。 Once I reach a combination that reaches a condition, I want to return. 一旦达到条件的组合,我想返回。

I am maintaining "state" of my combination and am backtracking where I should be (I think). 我正在维持合并的“状态”,并回溯到应该的位置(我认为)。

What am I doing wrong? 我究竟做错了什么?

class Combo:
    def __init__(self, list):
       self.staples = list

Combo has a property called "staples", consisting of a list of staple classes. 组合具有名为“装订”的属性,其中包括装订类别的列表。 I want to iterate over the list of staples in a decision tree to find an optimal number. 我想遍历决策树中的订书钉列表以找到最佳数量。

In this case, the optimal number is summed across the quantities of each staple instance in the list and stored/recalculated as a property on the Combo instance. 在这种情况下,最佳数量将在列表中每个订书钉实例的数量上相加,并作为组合实例上的属性进行存储/重新计算。

def IterateStaples(combo, target):        
  #Exit condition for combo dictionary
  if all(combo.diff[macro] < 2 for macro in combo.diff):    
    return combo;                            

  #iterate through all items in list
  for staple in combo.staples:                                  

    #Increment and calc conditions
    staple.increment()         
    combo.calcTotals()      
    combo.findDiff(target)

    #If exceeds target value, backtrack
    if combo.findConflict(target):                
      staple.decrement()
      combo.calcTotals()                
      combo.findDiff(target)              

    #Redundant exit condition to try and return
    elif all(combo.diff[macro] < 2 for macro in combo.diff):                                  
      return combo                

    #Recursive call
    else:        
      return IterateStaples(combo, target)
      staple.decrement()
      combo.calcTotals()
      combo.findDiff(target)

Your first if statement inside the for loop doesn't return anything. for循环内的第一个if语句不返回任何内容。 What it should return depends on your algorithm's logic: 返回的内容取决于算法的逻辑:

#If exceeds target value, backtrack
if combo.findConflict(target):                
   staple.decrement()
   combo.calcTotals()                
   combo.findDiff(target)
   return SOMETHING

Additionally, the last 3 lines won't ever get executed, they're after the return statement. 此外,最近3线永远不会得到执行,他们是 return的语句。

If I understand your code correctly (which is more difficult than usual, since you've not shown what most of the methods you're calling on combo and staple are), this should be what you want: 如果我正确地理解了您的代码(这比平时更困难,因为您没有显示要在combostaple上调用的大多数方法是什么),那么这应该是您想要的:

def IterateStaples(combo, target):        
    # base case
    if all(combo.diff[macro] < 2 for macro in combo.diff): # iterate on combo.diff.values()?
        return combo   # returning combo indicates success!

    for staple in combo.staples:
        staple.increment()                 # update state   
        combo.calcTotals()      
        combo.findDiff(target)

        if not combo.findConflict(target):  # skip recursing on invalid states
            result = IterateStaples(combo, target)    # recursive case
            if result is not None:      # if the recursion was successful, return the result
                return result

        staple.decrement()  # otherwise, undo the change to the state (backtrack)
        combo.calcTotals()     # these two lines might not be necessary when backtracking
        combo.findDiff(target) # since other branches will call them after staple.increment()

    return None # if we got to the end of the loop, explicitly return None to signal failure

The return None at the end is not strictly necessary, since None is the default return value if you don't return anything else. 最后没有严格要求return None ,因为如果您不返回其他任何内容,则None是默认的返回值。 I just think that it's better to be explicit about it. 我只是认为最好将其明确。

I'm following your code in returning combo on success (and extending it to returning None on failure). 我正在遵循您的代码,如果成功则返回combo (并将失败时扩展为返回None )。 Since the code mutates combo in place, you could just as well return True for success (in the base case at the top of the function) and False for failure (at the bottom of the function, after the end of the loop). 由于代码会原地改变combo ,因此您也可以返回True表示成功(在函数的顶部是基本情况),而False表示失败(在循环结束后在函数的底部)。 The recursive logic would pass on True results, and backtrack after False results. 递归逻辑将传递True结果,并在False结果之后回溯。 The top-level caller would need to check the combo instance they'd passed in for the actual solution if they got a True return value: 如果顶级调用者获得了True返回值,则需要检查传入的combo实例以获取实际的解决方案:

combo = Combo(something)
if IterateStaples(combo, target):
    do_stuff(combo) # success!

I was able to pass my own test case by incorporating a helper function in the following: 通过在下面合并一个辅助函数,我能够通过自己的测试用例:

Is this not backtracking? 这不是回溯吗? I implemented N-queens with a similar approach 我用类似的方法实现了N皇后

def IterateStaples(combo, target):        
  #iterate through all items in list
  bestCombo = []
  def helper(combo):
    for staple in combo.staples:                                      
      #Increment and calc conditions
      staple.increment()         
      combo.calcTotals()      
      combo.findDiff(target)    

      #If exceeds target value, backtrack
      if combo.findConflict(target):                      
        staple.decrement()
        combo.calcTotals()                
        combo.findDiff(target)                                        

      #Redundant exit condition to try and return
      elif all(combo.diff[macro] < 2 for macro in combo.diff):                                          
        bestCombo.append(deepcopy(combo))        
        return                

      #Recursive call
      else:        
        helper(combo)
        staple.decrement()
        combo.calcTotals()
        combo.findDiff(target)

  helper(combo)  

  return bestCombo

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM