使用嵌套值搜索树结构?

时间:2016-08-02 15:27:47

标签: python search recursion tree nested

输入树结构是按父/子帐户的层次顺序分隔的财务帐户列表。任何给定的帐户都可以有任意数量的父母/子女。在Python结构中,每个子节点都是一个可以包含任意数量的字典和/或文本值的列表。字典表示指向其他帐户的子项,而文本值表示没有其他后代的子项。下面是一些用JSON格式化的示例输入(测试它,请在Python中将其转换回来):

[  
   {  
      "Assets":[  
         {  
            "Bank":[  
               "Car",
               "House"
            ]
         },
         {  
            "Savings":[  
               "Emergency",
               {  
                  "Goals":[  
                     "Roof"
                  ]
               }
            ]
         },
         "Reserved"
      ]
   }
]

在幕后有一个输入文件,其中包含如下所示的帐户定义:

Assets:Bank:House
Assets:Savings:Emergency
Assets:Savigs:Goals:Roof

我有现有的代码来解析和创建上面看到的树结构。

目标:最终目标是通过搜索树来利用给定的字符串输入提供自动完成功能。使用上面的示例输入,以下输入将产生各自的输出:

"Assets" => ["Bank, "Savings", "Reserved"]
"Assets:Bank" => ["Car", "House"]
"Assets:Savings:Goals" => ["Roof"]

部分解决方案:递归是我被绊倒的地方。我能够创建可以处理“root”帐户的结果的代码,但我不确定如何使其递归以提供子帐户的结果。这是代码:

def search_tree(account, tree):
    # Check to see if we're looking for a root level account
    if isinstance(account, str) and ":" not in account:
        # Collect all keys in the child dictionaries
        keys = {}
        for item in tree:
            if isinstance(item, dict):
                keys[item.keys()[0]] = item

        # Check to see if the input matches any children
        if account in keys:
            # Collect all children of this account
            children = []

            for child in keys[account][account]:
                if isinstance(child, str):
                    children.append(child)
                else:
                    children.append(child.keys()[0])

            return children

# tree = .....
account = "Assets"
print search_tree(account, tree) # Would produce ["Bank", "Savings", "Reserved"]
# In the future I would provide "Assets:Bank" as the account string and get back the following: ["Car", "House"]

如何将此递归搜索到 n 的孩子?

2 个答案:

答案 0 :(得分:2)

我不会真正回答您的问题(关于您的特定标准输出要求),但我将帮助您了解如何搜索树结构

首先描述你的树形结构

  1. tree =节点列表
  2. nodeType1 =由nodeName => children
  3. 组成的字典
  4. nodeType2 =没有子节点的简单基本字符串(nodeName)(叶节点)
  5. 现在我们可以开始编写递归解决方案了

    def search(key,tree):
        if isinstance(tree,(list,tuple)): # this is a tree
            for subItem in tree: # search each "node" for our item
                result = search(key,subItem)
                if result:
                    return result
        elif isinstance(tree,dict): # this is really a node (nodeType1)
            nodeName,subTree = next(tree.iteritems())
            if nodeName == key: # match ... in your case the key has many parts .. .you just need the "first part"
                print "Found:",key
                return subTree
            else: # did not find our key so search our subtree
                return search(key,subTree)
    
        elif isinstance(tree,basestring): #leaf node
            if tree == key: # found our key leaf node
                print "Found",key
                return tree
    

    这实际上只是一个非常通用的解决方案,它可用于搜索单个条目(即“House”或“Accounts”...它不记录用于获得解决方案的路径)< / p>

    现在让我们回到检查您的问题陈述

    密钥是多部分密钥Part1:part2:part3 所以让我们开始解决这个问题

    def search_multipartkey(key,T,separator=":"):
        result = T
        for part in key.split(separator):
            result = search(part,result)
            if not result:
               print "Unable to find part:",part
               return False
            else:
               print "Found part %s => %s"%(part,result)
        return result
    

    你几乎可以肯定地改进了这一点,但这给了一个很好的起点(尽管它可能不像人们所希望的那样递归)

答案 1 :(得分:0)

不完整(超时,但我相信你会设法整合你的测试):

tree =  [
        {"Assets":  [
                    {"Bank":    [
                                "Car",
                                "House"
                                ]
                    },
                    {"Savings": [
                                "Emergency",
                                {"Goals":
                                        ["Roof"]
                                }
                                ]
                    },
                    "Reserved"
                    ]
      }
   ]



def search_tree(account, tree, level):
    """ """
    print("account", account)
    print("tree", tree)
    print("level", level)
    print("-------------")

    if account == []:
        return

    r = None
    for d in tree:
        print("a:",account[0])
        print("d:",d)
        try:
            newtree = d[account[0]]
            newaccount = account[1:]
            print("new:", newtree, newtree )
            r = search_tree(newaccount, newtree, level+1)
        except Exception as e:
            print("failed because:", e)
    return r

account = "Assets:Bank"
search_tree(account.split(":"), tree, 0)

输出:

> py -3 t.py
account ['Assets', 'Bank']
tree [{'Assets': [{'Bank': ['Car', 'House']}, {'Savings': ['Emergency', {'Goals': ['Roof']}]}, 'Reserved']}]
level 0
-------------
a: Assets
d: {'Assets': [{'Bank': ['Car', 'House']}, {'Savings': ['Emergency', {'Goals': ['Roof']}]}, 'Reserved']}
new: [{'Bank': ['Car', 'House']}, {'Savings': ['Emergency', {'Goals': ['Roof']}]}, 'Reserved'] [{'Bank': ['Car', 'House']}, {'Savings': ['Emergency', {'Goals': ['Roof']}]}, 'Reserved']
account ['Bank']
tree [{'Bank': ['Car', 'House']}, {'Savings': ['Emergency', {'Goals': ['Roof']}]}, 'Reserved']
level 1
-------------
a: Bank
d: {'Bank': ['Car', 'House']}
new: ['Car', 'House'] ['Car', 'House']
account []
tree ['Car', 'House']
level 2
-------------
a: Bank
d: {'Savings': ['Emergency', {'Goals': ['Roof']}]}
failed because: 'Bank'
a: Bank
d: Reserved
failed because: string indices must be integers

仍然没有测试,但返回你想要的(对于这个案例):

def search_tree(account, tree, level):
    """ """
    #print()
    #print()
    #print("account", account)
    #print("tree", tree)
    #print("level", level)
    #print("-------------")

    if account == []:
        #print("reached end")
        #print("tree", tree)
        return tree

    r = None
    for d in tree:
        #print("a:",account[0])
        #print("d:",d)
        try:
            newtree = d[account[0]]
            newaccount = account[1:]
            #print("new:", newtree, newtree )
            r = search_tree(newaccount, newtree, level+1)
        except Exception as e:
            #print("failed because:", e)
            pass
    return r

account = "Assets:Bank"
print( search_tree(account.split(":"), tree, 0) ) # --> ['Car', 'House']