我一直在使用imran给flatten 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就会进入这个...任何提示都会受到赞赏。
答案 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)