【问题标题】:Recursive theory: returning the first matching object in a nested set?递归理论:返回嵌套集中的第一个匹配对象?
【发布时间】:2015-02-10 02:58:11
【问题描述】:

我正在尝试编写代码,该代码将采用一个可以包含任意大量嵌套对象的对象,每个嵌套对象都可以包含嵌套对象,依此类推。我正在尝试编写一个函数来查找与给定条件匹配的 first 对象。我不在乎匹配所有对象。

Python 2 是这里的语言,但这个理论应该适用于任何语言。

class MyObject:
    myType = ""
    myChildren = list([])
    def __init__(self, t):
        self.myType = t

a = MyObject("top")
a.myChildren.append(MyObject("obj1"))
a.myChildren.append(MyObject("obj2"))
a.myChildren.append(MyObject("obj3"))
a.myChildren[1].myChildren.append(MyObject("objA"))
a.myChildren[1].myChildren.append(MyObject("objB"))
a.myChildren[1].myChildren.append(MyObject("objC"))
a.myChildren[1].myChildren[0].myChildren.append(MyObject("Sam"))
a.myChildren[1].myChildren[0].myChildren.append(MyObject("Max"))
a.myChildren[1].myChildren[0].myChildren.append(MyObject("Waldo"))
a.myChildren[1].myChildren[1].myChildren.append(MyObject("Adam"))
a.myChildren[1].myChildren[1].myChildren.append(MyObject("Waldo"))
a.myChildren[2].append("Waldo"))

此时我们应该有一个看起来像这样的递归树:

[top]
 |-- [obj1]
 |-- [obj2]
 |    |-- [objA]
 |    |    |-- [Sam]
 |    |    |-- [Max]
 |    |    \-- [Waldo]
 |    |-- [objB]
 |    |    |-- [Adam]
 |    |    \-- [Waldo]
 |    \-- [objC]
 \-- [obj3]
      \-- [Waldo]

所以现在,我想编写一个函数来查找并返回对 Waldo 的 first 实例的引用。如您所见,Waldo 可能不止一个。我只对top/obj2/objA/Waldo 实例感兴趣。

我过去做过的唯一递归代码使用递归返回来逐步返回更多内容。例如:将创建递归树的函数:

def printTree(rootObj,indentLevel=0):
    output = "%s%s\n" % (" "*indentLevel, rootObj.myType)
    for obj in rootObj:
        output += printTree(obj,indentLevel+1)
    return output

问题是,正如我所说,我只想要 第一个 实例,并且我想在那个时候停止遍历树。一旦树变大并且所需的对象位于树的早期某处,遍历整棵树的效率将非常低。

我似乎无法弄清楚实现这一点的逻辑是如何运作的。我最初的想法是这样的:

def findFirst(rootObj, desiredType):
    # test this object first
    if (rootObj.myType == desiredType): 
        return rootObj
    # we are not the correct object, so now test all sub-objects.
    for (obj in rootObj):
        if (findFirst(obj,desiredType) is not None):
            return obj
    return None # nothing was found

然而这并不完全奏效。因为它只是返回第一个对象,即使它不匹配。

有人可以帮助阐明完成此操作所需的逻辑吗?

编辑:一些澄清。递归的方法是我们将尽可能深入到树中,然后为每个对象返回。该列表也是有序的。因此,例如,上述树的递归路径将是:

top -> obj1 -> obj2 -> objA -> Sam -> Max -> Waldo -> objB -> Adam -> Waldo -> objC -> obj3 -> Waldo

另外,我确实给出了一个自创建对象的示例,但是,我想在其中使用此代码的应用程序中的对象是动态创建的;因此,序列化或转换对象树最终会遍历整个树,这会减慢速度,因为我们是根据状态生成动态对象。

查看我要查找的内容的一个好方法是递归文件搜索功能。假设我们在磁盘上有一个文件夹,我们希望该文件夹中的第一个文件 anywhere 根据正则表达式匹配给定的文件名并且具有给定条件内的大小。 (这意味着我们必须对每个对象进行计算,我们不能简单地检查变量并根据它们进行过滤。)但是,如果该文件位于根目录中,我们不想解析整个驱动器的目录结构或在我们来到的第一个目录中。我的问题的真正精神是“一旦找到符合您所需条件的东西,您如何才能摆脱这个递归循环?”

【问题讨论】:

  • 那么您希望第一次出现关于子索引值的情况吗?我认为第一次出现的是 waldo,它落在树深处 2 层,而不是位于第 3 层的 waldo(但附加在索引 1)
  • 不,我们在走树的时候,先走最深的方法遇到的第一个物体。换句话说,我不想检查深度 1 的 all,然后检查深度 2 的所有,依此类推。相反,我想检查深度 1 对象,但是当遇到另一个层时,first 下降到该层,然后再进入下一个级别 1 对象。

标签: recursion python-2.x


【解决方案1】:

一个好的方法是使用JSON (link) 来表示所需的结构,然后对其进行解析并基于此创建一个python 对象。查看here 了解更多信息。

【讨论】:

  • 我在原始帖子中没有提到,但我正在编写的代码将处理预先存在的对象,而不是我明确创建并可以稍后解析的对象。想象一下,我们正在使用 XML DOM 执行此操作。 (这不是 XML DOM,但同样的想法 - 对象是提供给我的。)
  • 首先,在你的问题中包含这个,我认为这很重要。另外,您确定您的对象不是标准解析格式(如JSON)吗?
【解决方案2】:

您可以使递归函数在找到它时返回一个值(您要查找的对象)。这样,您只需像正常一样运行递归函数,并在函数返回某些内容时结束。

伪代码:

function findFirst(rootObj, desiredType){

   var objectToReturn

   //check current object, return if found
   if (rootObj.myType == desiredType)
       return rootObj

    // Return null if no children and this wasnt desired type
    if(rootObj.hasChildren == false)
        return null

    // Has children, not yet found anything
    // return the recursive result
    // this will return null or a value
    // if we get a null, keep looking 
    // otherwise return the value and be done.
    for(obj in rootObj){
        objectToReturn = findFirst(obj, desiredType)

        // if the result is a value, return it
        if(objectToReturn != null)
            return objectToReturn 
        // otherwise, keep looking            
    }               
}

类似的东西。关键是一旦你找到一个值,你就会返回它。如果您返回任何值,则整个递归函数将停止,因为返回了一个值。您只需要确保在内存密集型任务中将递归方法发送回之前检查返回值。

【讨论】:

    猜你喜欢
    • 2019-02-15
    • 2020-01-26
    • 1970-01-01
    • 2012-02-12
    • 2021-09-12
    • 1970-01-01
    • 2021-01-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多