假设你有一本这样的字典:

{'a': 1,
 'c': {'a': 2,
       'b': {'x': 5,
             'y' : 10}},
 'd': [1, 2, 3]}

你会如何把它平摊成这样:

{'a': 1,
 'c_a': 2,
 'c_b_x': 5,
 'c_b_y': 10,
 'd': [1, 2, 3]}

当前回答

你可以使用递归来平展你的字典。

import collections


def flatten(
    nested_dict,
    seperator='.',
    name=None,
):
    flatten_dict = {}

    if not nested_dict:
        return flatten_dict

    if isinstance(
        nested_dict,
        collections.abc.MutableMapping,
    ):
        for key, value in nested_dict.items():
            if name is not None:
                flatten_dict.update(
                    flatten(
                        nested_dict=value,
                        seperator=seperator,
                        name=f'{name}{seperator}{key}',
                    ),
                )
            else:
                flatten_dict.update(
                    flatten(
                        nested_dict=value,
                        seperator=seperator,
                        name=key,
                    ),
                )
    else:
        flatten_dict[name] = nested_dict

    return flatten_dict


if __name__ == '__main__':
    nested_dict = {
        1: 'a',
        2: {
            3: 'c',
            4: {
                5: 'e',
            },
            6: [1, 2, 3, 4, 5, ],
        },
    }

    print(
        flatten(
            nested_dict=nested_dict,
        ),
    )

输出:

{
   "1":"a",
   "2.3":"c",
   "2.4.5":"e",
   "2.6":[1, 2, 3, 4, 5]
}

其他回答

如果你使用pandas,有一个函数隐藏在pandas.io.json中。_normalize1调用nested_to_record来完成这个操作。

from pandas.io.json._normalize import nested_to_record    

flat = nested_to_record(my_dict, sep='_')

1在熊猫0.24版本。X及以上版本使用panda .io.json.normalize(不带_)

实际上,我最近写了一个名为cherrypicker的包来处理这种确切的事情,因为我必须经常这样做!

我认为下面的代码会给你你想要的东西:

from cherrypicker import CherryPicker

dct = {
    'a': 1,
    'c': {
        'a': 2,
        'b': {
            'x': 5,
            'y' : 10
        }
    },
    'd': [1, 2, 3]
}

picker = CherryPicker(dct)
picker.flatten().get()

您可以使用以下方法安装软件包:

pip install cherrypicker

...在https://cherrypicker.readthedocs.io上有更多的文档和指导。

其他方法可能更快,但这个包的优先级是使这些任务变得容易。如果你确实有一个很大的对象列表要扁平化,你也可以告诉CherryPicker使用并行处理来加快速度。

使用生成器的Python 3.3解决方案:

def flattenit(pyobj, keystring=''):
   if type(pyobj) is dict:
     if (type(pyobj) is dict):
         keystring = keystring + "_" if keystring else keystring
         for k in pyobj:
             yield from flattenit(pyobj[k], keystring + k)
     elif (type(pyobj) is list):
         for lelm in pyobj:
             yield from flatten(lelm, keystring)
   else:
      yield keystring, pyobj

my_obj = {'a': 1, 'c': {'a': 2, 'b': {'x': 5, 'y': 10}}, 'd': [1, 2, 3]}

#your flattened dictionary object
flattened={k:v for k,v in flattenit(my_obj)}
print(flattened)

# result: {'c_b_y': 10, 'd': [1, 2, 3], 'c_a': 2, 'a': 1, 'c_b_x': 5}

这不完全是OP所要求的,但很多人都来这里寻找方法来平坦现实世界的嵌套JSON数据,这些数据可以有嵌套的键值JSON对象和数组,数组内的JSON对象等等。JSON不包括元组,所以我们不必担心这些。

我找到了@roneo对@Imran发布的答案的列表包含评论的实现:

https://github.com/ScriptSmith/socialreaper/blob/master/socialreaper/tools.py#L8

import collections
def flatten(dictionary, parent_key=False, separator='.'):
    """
    Turn a nested dictionary into a flattened dictionary
    :param dictionary: The dictionary to flatten
    :param parent_key: The string to prepend to dictionary's keys
    :param separator: The string used to separate flattened keys
    :return: A flattened dictionary
    """

    items = []
    for key, value in dictionary.items():
        new_key = str(parent_key) + separator + key if parent_key else key
        if isinstance(value, collections.MutableMapping):
            items.extend(flatten(value, new_key, separator).items())
        elif isinstance(value, list):
            for k, v in enumerate(value):
                items.extend(flatten({str(k): v}, new_key).items())
        else:
            items.append((new_key, value))
    return dict(items)

测试:

flatten({'a': 1, 'c': {'a': 2, 'b': {'x': 5, 'y' : 10}}, 'd': [1, 2, 3] })

>> {'a': 1, 'c.a': 2, 'c.b.x': 5, 'c.b.y': 10, 'd.0': 1, 'd.1': 2, 'd.2': 3}

这做的工作,我需要做:我扔任何复杂的json在这,它为我扁平化。

所有学分发送至https://github.com/ScriptSmith。

这里有一个使用堆栈的解决方案。没有递归。

def flatten_nested_dict(nested):
    stack = list(nested.items())
    ans = {}
    while stack:
        key, val = stack.pop()
        if isinstance(val, dict):
            for sub_key, sub_val in val.items():
                stack.append((f"{key}_{sub_key}", sub_val))
        else:
            ans[key] = val
    return ans