偶然看见一个有意思的面试题,有下面一组这样的json数据,根据输入的name,找出对应的id
数据如下:
{
"message": "Success",
"result": {
"root": [
{
"children": [
{
"children": [
{
"children": [],
"id": 3877,
"name": "自动化测试组织0101"
}
],
"id": 516,
"name": "自动化测试组织01"
},
{
"children": [
{
"children": [
{
"children": [],
"id": 3879,
"name": "自动化测试组织020101"
}
],
"id": 3878,
"name": "自动化测试组织0201"
}
],
"id": 517,
"name": "自动化测试组织02"
}
],
"id": 3159,
"name": "自动化测试专用机构"
}
]
},
"status": 0,
"success": "True"
}
接下来,开始对问题进行分析
我们把这个问题拆分为2个部分,第一个部分是取root数据,第二个部分是编写递归方法
,并查找对应的name
def find_name(name: str):
"""
方法1:假设name不重复
:param name:
:return:
"""
if data.get("Success"):
# 请求成功
root = data.get("result", {}).get("root", [])
return find_name(root, name)
return None
根据data里面的Success字段判断是否请求到了数据,拿到了我们就取出字典里面的root数据
这样我们只需要去root里面搜刮一顿,调用find_id_by_name方法拿到最终id即可
def find_id_by_name(root: list, name: str):
"""
:param root:
:param name:
:return:
"""
for r in root:
if r.get("name") == name:
return r.get("id")
children = r.get("children")
result = find_id_by_name(children, name)
if result is not None:
return result
return None
-
for r in root,如果root为空数组的话,那么会直接不走for循环,return None
-
当r.get("name")与我们传入的name相等的话,直接返回这一层的id
-
能走到children这一步,说明这一层没有咱们想要的
-
获取children
-
接着我们把children这一层当作root,继续调用
find_id_by_name
方法
接下来说说递归存在的问题
-
不慎的话容易死循环
但这不是递归的错,就算是while,你不改变循环条件
,也会死循环。
2.堆栈太长
这个是递归被人诟病的地方,如果遇到深度几千万层
的数据,递归最终会引起内存不足,导致程序崩溃。
避免的方式
第二个问题,如果是层级很深的情况,不建议使用递归。
第一个问题的话,我们一定要注意递归的结束条件。在上述问题里面,递归结束的条件就是找到name,也就是result不为空,很好理解,因为为空说明没找到,不把整个数据给你你翻个底朝天就不会停止。
其实还有一个隐形的条件,就是for r in root,这里有一个隐形的条件是root为空数组,这样的话,这个递归方法也会结束,直接return None