压缩嵌套的Python词典,压缩密钥,并使用dicts

时间:2017-12-01 22:03:06

标签: python dictionary

我一直在使用imranflatten nested Python dictionaries, compressing keys的好答案,并试图想出一种方法来进一步压扁可能的字典在词典项目 list 值内。
(当然,由于我的数据通常来自XML,因此也可以递归...)

from pprint import pprint
from collections import MutableMapping

def flatten(d, parent_key='', sep='_'):
    items = []
    for k, v in d.items():
        new_key = parent_key + sep + k if parent_key else k
        if isinstance(v, MutableMapping):
            items.extend(flatten(v, new_key, sep=sep).items())
        else:
            items.append((new_key, v))
    return dict(items)

给出这样的字典d

d = {"a": 1,
     "b": 2,
     "c": {"sub-a": "one",
           "sub-b": "two",
           "sub-c": "thre"}}

这很有效:

pprint(flatten(d))

        {'a': 1,
         'b': 2,
         'c_sub-a': 'one',
         'c_sub-b': 'two',
         'c_sub-c': 'thre'}

但是,我想进一步重复显示dict项目的列表值,并检查列表中的每个字典是否可以进一步展平。

以下是c-list作为嵌套列表值的示例输入示例:

d = {"a": 1,
     "b": 2,
     "c-list": [
         {"id": 1, "nested": {"sub-a": "one", "sub-b": "two", "sub-c": "thre"} },
         {"id": 2, "nested": {"sub-a": "one", "sub-b": "two", "sub-c": "thre"} },
         {"id": 3, "nested": {"sub-a": "one", "sub-b": "two", "sub-c": "thre"} }]}

这是我目前使用上述功能获得的内容:

pprint(flatten(d))

{'a': 1,
 'b': 2,
 'c-list': [{'id': 1, 'nested': {'sub-a': 'one', 'sub-b': 'two', 'sub-c': 'thre'}},
            {'id': 2, 'nested': {'sub-a': 'one', 'sub-b': 'two', 'sub-c': 'thre'}},
            {'id': 3, 'nested': {'sub-a': 'one', 'sub-b': 'two', 'sub-c': 'thre'}}]}

以下是我要查找的输出,保留原始flatten()的所有功能:

{'a': 1,
 'b': 2,
 'c-list': [{'id': 1, 'nested_sub-a': 'one', 'nested_sub-b': 'two', 'nested_sub-c': 'thre'},
            {'id': 2, 'nested_sub-a': 'one', 'nested_sub-b': 'two', 'nested_sub-c': 'thre'},
            {'id': 3, 'nested_sub-a': 'one', 'nested_sub-b': 'two', 'nested_sub-c': 'thre'}]}

我正在努力弄清楚如何以递归的方式重新组装"当它包含列表时,dict就会进入这个...任何提示都会受到赞赏。

2 个答案:

答案 0 :(得分:2)

你真的很接近,如果一个值是一个列表,那么需要一行来获得flatten的递归版本:

items.append((new_key, map(flatten, v)))  # for python 2.x
# or
items.append((new_key, list(map(flatten, v))))  # for python 3.x

所以,你只需以递归方式调用每个元素上的函数

以下是flatten的样子:

def flatten(d, parent_key='', sep='_'):
    items = []
    for k, v in d.items():
        new_key = '{0}{1}{2}'.format(parent_key,sep,k) if parent_key else k
        if isinstance(v, MutableMapping):
            items.extend(flatten(v, new_key, sep=sep).items())
        elif isinstance(v, list):
            # apply itself to each element of the list - that's it!
            items.append((new_key, map(flatten, v)))
        else:
            items.append((new_key, v))
    return dict(items)

此解决方案可以处理列表中任意深度的列表

答案 1 :(得分:1)

只需为列表中的每个词典做一个展平,将它们收集到一个新列表中,并使用原始密钥将其附加到items

def flatten(d, parent_key='', sep='_'):
        items = []
        for k, v in d.items():
            new_key = parent_key + sep + k if parent_key else k
            if isinstance(v, MutableMapping):
                items.extend(flatten(v, new_key, sep=sep).items())
            elif type(v) == list:
                items.append((new_key, [flatten(i) for i in v]))
            else:
                items.append((new_key, v))
        return dict(items)