【问题标题】:How can I create a flat dictionary from a nested dictionary whose keys are a subset of a reference dictionary?如何从其键是参考字典子集的嵌套字典创建平面字典?
【发布时间】:2018-06-10 08:21:12
【问题描述】:

我正在创建一个嵌套引用字典来记录数据字典可能具有的所有可能键以及相应的值,这些值是平面字典中要使用的所有键。

数据字典的键始终是参考字典的键的子集。平面字典的键始终是参考字典的值集的子集。

换句话说,给定一个具有如下赋值的参考字典:

reference['agent']['address'] = 'agentaddress'
reference['agent']['zone']['id'] = 'agentzoneid'
reference['eventid'] = 'eventid'
reference['file']['hash'] = 'filehash'
reference['file']['name'] = 'filename'

还有一个像这样赋值的数据字典:

nested['agent']['address'] = '172.16.16.16'
nested['eventid'] = '1234566778'
nested['file']['name'] = 'reallybadfile.exe'

代码应该生成一个字典,可以这样分配:

flat['agentaddress'] = '172.16.16.16'
flat['eventid'] = '1234566778'
flat['filename'] = 'reallybadfile.exe'

我永远无法知道嵌套字典中的哪些字段会被填充,哪些不会,但我可以知道参考字典中的映射。

我希望我需要使用递归将字典遍历到子字典中,并可能需要某种间接来分别从参考字典值和嵌套字典键创建平面字典键和值。

但是,我还不能生成任何有意义的代码。

也许从非常高的层次看,它可能看起来像这样:

def this(ref, nest, flat, *args):
    for (k,v) in reference:
        if type(v) is dict:
            this(?, ?, ?, ?)
        elif nested[path][to][k]:      
            flat[reference[path][to][k]] = nested[path][to][k]

其中[path][to][k] 代表某种方式进行间接,而*args 是我将传递给递归函数的东西,这样我就有办法获得足够的上下文来通过字典的嵌套性进行参考到我需要的键和值。

【问题讨论】:

  • reference['agent']['address']='agentaddress' 将崩溃,除非分配了reference['agent']。但是,我没有在问题中看到该分配。因此,这可能是您开始的地方。

标签: python dictionary recursion generator indirection


【解决方案1】:

使用generator,这相当简单:

代码:

def make_flat_tuples(data, ref):
    for k, v in data.items():
        if isinstance(v, dict):
            for x in make_flat_tuples(v, ref[k]):
                yield x
        else:
            yield ref[k], v

flat = dict(make_flat_tuples(nested, reference))

测试代码:

from collections import defaultdict

reference = defaultdict(dict)
reference['agent'] = defaultdict(dict)

reference['agent']['address'] = 'agentaddress'
reference['agent']['zone']['id'] = 'agentzoneid'
reference['eventid'] = 'eventid'
reference['file']['hash'] = 'filehash'
reference['file']['name'] = 'filename'

nested = defaultdict(dict)

nested['agent']['address'] = '172.16.16.16'
nested['eventid'] = '1234566778'
nested['file']['name'] = 'reallybadfile.exe'

print(dict(make_flat_tuples(nested, reference)))

结果:

{
    'agentaddress': '172.16.16.16', 
    'eventid': '1234566778', 
    'filename': 'reallybadfile.exe'
}

【讨论】:

  • 在你回答了这个问题之后,我意识到两件事:1. 这是我问题的答案,2. 我想问一个稍微不同的问题。嵌套字典也可能包含引用中不存在的值。在这种情况下,它们应该简单地从平面字典中省略。我发现我可以在您的解决方案中添加一行来完成此操作:在第一个 for 循环之后的行中:if k not in ref: 后跟 continue
【解决方案2】:

@StephenRauch 的回答很好,如果您不想使用生成器,只需重新格式化如下:

# r=reference, n=nested, f=final
def buildDict(r, n, f):
    for key in n.keys():
        if isinstance(n[key], dict):
            buildDict(r.get(key), n[key], f)
        else:
            if r.get(key):
                f[r.get(key)] = n[key]

【讨论】:

    猜你喜欢
    • 2018-11-09
    • 2018-03-27
    • 1970-01-01
    • 2015-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多