使用嵌套键对Dict进行Python递归搜索

ok1*_*ump 6 python recursion dictionary global list

我最近不得不用嵌套的字典/列表组合解决实际数据系统中的问题.我在这方面工作了很长一段时间并提出了一个解决方案,但我非常不满意.我不得不求助于使用globals()和命名的临时全局参数.

我不喜欢使用全局变量.这只是要求注射漏洞.我觉得必须有更好的方法来执行这项任务而不诉诸全局变量.

问题数据集:

d = {
    "k":1,
    "stuff":"s1",
    "l":{"m":[
        {
            "k":2,
            "stuff":"s2",
            "l":None
        },
        {
            "k":3,
            "stuff":"s3",
            "l":{"m":[
                {
                    "k":4,
                    "stuff":"s4",
                    "l":None
                },
                {
                    "k":5,
                    "stuff":"s5",
                    "l":{"m":[
                        {
                            "k":6,
                            "stuff":"s6",
                            "l":None
                        },
                    ]}
                },
            ]}
        },
    ]}
}
Run Code Online (Sandbox Code Playgroud)

期望的输出:

[{'k': 1, 'stuff': 's1'},
 {'k': 2, 'stuff': 's2'},
 {'k': 3, 'stuff': 's3'},
 {'k': 4, 'stuff': 's4'},
 {'k': 5, 'stuff': 's5'},
 {'k': 6, 'stuff': 's6'}]
Run Code Online (Sandbox Code Playgroud)

我的解决方案

def _get_recursive_results(d, iter_key, get_keys):
    if not 'h' in globals():
        global h
        h = []
    h.append({k:d.get(k) for k in get_keys})

    d2 = d.copy()
    for k in iter_key:
        if not d2:
            continue
        d2 = d2.get(k)

    for td in d2:
        d3 = td.copy()
        for k in iter_key:
            if not d3:
                continue
            d3 = d3.get(k)

        if d3:
            return _get_recursive_results(td, iter_key, get_keys)
        h.append({k:td.get(k) for k in get_keys})
    else:
        l = [k for k in h]
        del globals()['h']
        return l
Run Code Online (Sandbox Code Playgroud)

按如下方式调用我的函数会返回所需的结果:

_get_recursively(d, ['l','m'], ['k','stuff'])
Run Code Online (Sandbox Code Playgroud)

我将如何构建更好的解决方案?

Mik*_*ler 7

这是一个稍微修改过的版本,没有使用全局变量.设置hNone 默认,并为第一次调用一个新的列表_get_recursive_results().稍后h在递归调用中提供作为参数_get_recursive_results():

def _get_recursive_results(d, iter_key, get_keys, h=None):
    if h is None:
        h = []
    h.append({k:d.get(k) for k in get_keys})
    d2 = d.copy()
    for k in iter_key:
        if not d2:
            continue
        d2 = d2.get(k)
    for td in d2:
        d3 = td.copy()
        for k in iter_key:
            if not d3:
                continue
            d3 = d3.get(k)
        if d3:
            return _get_recursive_results(td, iter_key, get_keys, h)
        h.append({k:td.get(k) for k in get_keys})
    else:
        l = [k for k in h]
        return l
Run Code Online (Sandbox Code Playgroud)

现在:

>>> _get_recursive_results(d, ['l','m'], ['k','stuff'])
[{'k': 1, 'stuff': 's1'},
 {'k': 2, 'stuff': 's2'},
 {'k': 3, 'stuff': 's3'},
 {'k': 4, 'stuff': 's4'},
 {'k': 5, 'stuff': 's5'},
 {'k': 6, 'stuff': 's6'}]
Run Code Online (Sandbox Code Playgroud)

不需要复制中间词.这是一个没有复制的进一步修改版本:

def _get_recursive_results(d, iter_key, get_keys, h=None):
    if h is None:
        h = []
    h.append({k: d.get(k) for k in get_keys})
    for k in iter_key:
        if not d:
            continue
        d = d.get(k)
    for td in d:
        d3 = td
        for k in iter_key:
            if not d3:
                continue
            d3 = d3.get(k)
        if d3:
            return _get_recursive_results(td, iter_key, get_keys, h)
        h.append({k: td.get(k) for k in get_keys})
    else:
        return h
Run Code Online (Sandbox Code Playgroud)

  • 我仍然不确定为什么在for循环中需要克隆dict这么多次,如果没有对它进行修改? (2认同)
  • 是的,dict副本实际上没有必要. (2认同)

AKS*_*AKS 5

这不是通用的,但它完成了工作:

def parse_tree(d, keys):
   result = [{key: d[key] for key in keys}]
   l = d.get('l', None)
   if l is not None:
       entries = l.get('m', [])
       for entry in entries:
           result.extend(parse_tree(entry))
   return result


>>> parse_tree(d, ['k', 'stuff'])
[{'k': 1, 'stuff': 's1'},
 {'k': 2, 'stuff': 's2'},
 {'k': 3, 'stuff': 's3'},
 {'k': 4, 'stuff': 's4'},
 {'k': 5, 'stuff': 's5'},
 {'k': 6, 'stuff': 's6'}]
Run Code Online (Sandbox Code Playgroud)