任何更好的方法来展平和重建嵌套字典

时间:2017-04-22 23:29:10

标签: python dictionary

我自己发布了一个解决方案,但我对它不满意,这太复杂了。

有时候,我们需要压扁一个dict,有时反过来,例如: 嵌套的dict看起来像这样:

{'a': 'A', 'b': {'c': 'BC', 'd': [4, 44, 444]}}

和一个扁平的词典:

{'a': 'A', 'b__c': 'BC', 'b__d': [4, 44, 444]}

我们可以看到,在这种情况下,我们使用双下划线来表示嵌套级别。

我写了两个函数来做这些,请检查我发布的答案,但我仍然更喜欢任何robost第三方库或任何其他想法来使这两个函数变为eaiser?

而且除了之外,我还想知道什么是压扁值的正确方法,哪种类型是一个填充dict对象的列表?让我们这样说吧,如果我们用dicts intead替换数字4,44,444那么应该是什么应该是扁平的dict。

2 个答案:

答案 0 :(得分:0)

我写了两个函数来转换flatten和嵌套dict,但我更喜欢找一些robost lib来处理这些情况。

def flatten(nested_dict, result=None, prefix=''):
    from collections import OrderedDict
    if result is None:
        result = dict()
    for k, v in nested_dict.items():
        new_k = '__'.join((prefix, k)) if prefix else k
        if not (isinstance(v, dict) or isinstance(v, OrderedDict)):
            result.update({new_k: v})
        else:
            flatten(v, result, new_k)
    return result


def rebuild(flatten_dict, result=None):
    from collections import defaultdict
    import json

    def tree():
        return defaultdict(tree)

    def rec(keys_iter, value):
        _r = tree()
        try:
            _k = next(keys_iter)
            _r[_k] = rec(keys_iter, value)
            return _r
        except StopIteration:
            return value

    if result is None:
        result = dict()

    for k, v in flatten_dict.items():
        keys_nested_iter = iter(k.split('__'))
        cur_level_dict = result
        while True:
            try:
                k = next(keys_nested_iter)
                if k in cur_level_dict:
                    cur_level_dict = cur_level_dict[k]
                else:
                    cur_level_dict[k] = json.loads(json.dumps(rec(keys_nested_iter, v)))
            except StopIteration:
                break

    return result


if __name__ == "__main__":
    my_dict = {'a': 'A',
               'b':
                   {
                       'd': [4, 44, 444],
                       'c': 'BC'
                   }
               }

    my_flatten_dict = flatten(my_dict)
    assert my_flatten_dict == {'a': 'A', 'b__c': 'BC', 'b__d': [4, 44, 444]}

    my_nested_dict = rebuild(my_flatten_dict)
    assert my_nested_dict == {'a': 'A', 'b': {'c': 'BC', 'd': [4, 44, 444]}}

答案 1 :(得分:0)

虽然不是你应该做的事情,但你可以使用json.dumps将其更改为字符串并使用re.sub来执行操作< / p>

import json, re
d = {'a': 'A', 'b': {'c': 'BC', 'd': [4, 44, 444]}}
def flatten(to_flat):
    return json.loads(re.sub('\}+','}',re.sub('":? *\{"', '__', json.dumps(d))))
print(flatten(d))
# prints {'a': 'A', 'b__c': 'BC', 'd': [4, 44, 444]}

rebuilt函数存在问题,您如何知道近距离大括号的位置?你不能。但如果它总是位于最后,你可以这样做:

def rebuilt(to_rebuilt):
    to_rebuilt = re.sub('__', '": {"', json.dumps(to_rebuilt))
    return re.sub('\}','}'*to_rebuilt.count("{"),to_rebuilt)

print(rebuilt(flatten(d)))
# prints {'a': 'A', 'b': {'c': 'BC', 'd': [4, 44, 444]}}