如何从嵌套字典的键构建路径?

时间:2019-04-04 23:34:35

标签: python python-3.x

我正在编写一个脚本,该脚本通过MQTT网络广播许多数据流。我正在尝试将嵌套字典的键转换为一个字符串,然后将其用作MQTT广播频道。数据每秒都已经格式化为嵌套字典,如下所示:

my_dict = { 'stream1': { 'dataset1': { 'value1': 123.4}},
                         'dataset2': { 'value1': 123.4,
                                       'value2': 567.8},
            'stream2': { 'dataset3': { 'value4': 910.2}},
            'stream3': {               'value5': 'abcd'}}

我已经缩进以增加可读性,实际数据中没有多余的空格。如您所见,它具有多个级别,并非所有级别都具有相同数量的值,并且某些值键是重复的。另外,一个层次比其他层次浅,但如果可以使问题更容易解决,我可以轻松地将其设置为与其他层次相同的深度。

上面的字典应该提供如下输出:

("stream1/dataset1/value1", "stream1/dataset2/value1", ..., "stream3/value5")

,依此类推。

我觉得递归可能是一个很好的解决方案,但是我不确定在我通过结构时如何维护键的有序列表,以及确保击中结构中的每个项目并生成一个每个基本级别项目的新路径(请注意,缺少“ stream1 / dataset1”)。

这是我到目前为止的代码:

my_dict = { as defined above }

def get_keys(input_dict, path_list, current_path):
    for key, value in input_dict.items():
        if isinstance(value, dict):
            current_path += value
            get_keys(value, path_list, current_path)
        else:
            path = '/'.join(current_path)
            path_list.append(path)

my_paths = []
cur_path = []
get_keys(my_dict, my_paths, cur_path)
[print(p) for p in my_paths]

2 个答案:

答案 0 :(得分:2)

这是使用yield将函数转换为生成器的绝佳机会。生成器可以产生很多项,并且行为很像列表或其他可迭代项。调用者遍历其返回值,并在每次迭代中获得一个产生项,直到函数返回。

def get_keys(input_dict):
    for key, value in input_dict.items():
        if isinstance(value, dict):
            for subkey in get_keys(value):
                yield key + '/' + subkey
        else:
            yield key

for key in get_keys(my_dict):
    print(key)

for外部循环中,每个值可以是dict或纯值。如果它是一个普通值,则只需生成密钥。如果是字典,请对其进行迭代,并将key + '/'放在每个子键的前面。

令人高兴的是,您不必维护任何状态。 path_listcurrent_path不见了。 get_keys()只是一个接一个地产生字符串,而yield语句和递归循环使键的扁平化自然地消失了。

stream1/dataset1/value1
dataset2/value1
dataset2/value2
stream2/dataset3/value4
stream3/value5

答案 1 :(得分:2)

您可以为此使用生成器:

def convert(d):
    for k, v in d.items():
        if isinstance(v, dict):
            yield from (f'{k}/{x}' for x in convert(v))
        else:
            yield k

考虑到您的预期输出,您在示例数据中似乎花括号}的位置错误,但是使用了以下测试数据:

my_dict = { 'stream1': { 'dataset1': { 'value1': 123.4},
                         'dataset2': { 'value1': 123.4,
                                       'value2': 567.8}},
            'stream2': { 'dataset3': { 'value4': 910.2}},
            'stream3': {               'value5': 'abcd'}}

这是输出:

print(list(convert(d)))
# ['stream1/dataset1/value1', 'stream1/dataset2/value1', 'stream1/dataset2/value2', 'stream2/dataset3/value4', 'stream3/value5']