Python 3:扁平化嵌套词典和词典中的列表



我正在处理一个复杂的嵌套字典和列表数据结构。我需要平展数据并将所有嵌套项目带到级别 0。请参阅以下示例以更清晰:

{a:1,b:2,c:{c1:[{c11:1,c12:2,c13:3},{c21:1,c22:2,c23:3}],d1:[{d11:1,d12:2,d13:3},{d21:1,d22:2,d23:3}]},x:1,y:2}

我需要将其扁平化为:

{a:1,b:2,c_c1_c11:1, c_c1_c12:2,c_c1_c13:3,c_c1_c21:1,c_c1_c22:2,c_c1_c23:3, c_d1,d11:1...and so on}

我参考了这篇文章的第一个答案,但它只有在我有嵌套词典时才有效,而不是如果列表嵌套在词典中并且更多词典嵌套在这些列表中。

我稍微修改了代码以适应我的用例,但这段代码不起作用

def flattenDict(d):
node_map = {}
node_path = []
def nodeRecursiveMap(d, node_path):
for key, val in d.items():
if ((type(val) is not dict)&(type(val) is not list)): 
node_map['_'.join(node_path + [key])] = val
if type(val) is list:
def nodeListRecursion(val,node_path):
for element in val:
if ((type(element) is not dict)&(type(element) is not list)) : node_map['_'.join(node_path + [key])] = element
if type(element) is list: nodeListRecursion(element,node_map)
if type(element) is dict: nodeRecursiveMap(element, node_path + [key])
nodeListRecursion(val,node_path)
if type(val) is dict: nodeRecursiveMap(val, node_path + [key])
nodeRecursiveMap(d, node_path)
return node_map

当我将代码粘贴到此处时,缩进变得混乱。但我真的很感激这里的任何帮助。

我认为你把事情复杂化了。 您从字典开始,其中包含键和值。 它的值要么是字典,要么是你想要递归的字典列表,要么不是,在这种情况下,你想不理会它。 所以:

def flatten(d):
out = {}
for key, val in d.items():
if isinstance(val, dict):
val = [val]
if isinstance(val, list):
for subdict in val:
deeper = flatten(subdict).items()
out.update({key + '_' + key2: val2 for key2, val2 in deeper})
else:
out[key] = val
return out

给我

In [34]: nested = {'a': 1, 'b': 2, 'c': {'c1': [{'c11': 1, 'c12': 2, 'c13': 3}, {'c21': 1, 'c22': 2, 'c23': 3}], 'd1': [{'d11': 1, 'd12': 2, 'd13': 3}, {'d21': 1, 'd22': 2, 'd23': 3}]}, 'x': 1, 'y': 2}
In [35]: flatten(nested)
Out[35]: 
{'a': 1,
'b': 2,
'c_c1_c11': 1,
'c_c1_c12': 2,
'c_c1_c13': 3,
'c_c1_c21': 1,
'c_c1_c22': 2,
'c_c1_c23': 3,
'c_d1_d11': 1,
'c_d1_d12': 2,
'c_d1_d13': 3,
'c_d1_d21': 1,
'c_d1_d22': 2,
'c_d1_d23': 3,
'x': 1,
'y': 2}

在我的项目中,我正在使用 DSM 答案中的函数的更新版本来平展可能包含其他字典或字典列表或字典列表的字典。我希望这会有所帮助。

def flatten(input_dict, separator='_', prefix=''):
output_dict = {}
for key, value in input_dict.items():
if isinstance(value, dict) and value:
deeper = flatten(value, separator, prefix+key+separator)
output_dict.update({key2: val2 for key2, val2 in deeper.items()})
elif isinstance(value, list) and value:
for index, sublist in enumerate(value, start=1):
if isinstance(sublist, dict) and sublist:
deeper = flatten(sublist, separator, prefix+key+separator+str(index)+separator)
output_dict.update({key2: val2 for key2, val2 in deeper.items()})
else:
output_dict[prefix+key+separator+str(index)] = value
else:
output_dict[prefix+key] = value
return output_dict

更新了 DSM 答案,通过将索引与键连接起来,支持具有相同键的字典列表,而不会增加代码的复杂性。

代码

def flatten(d):
out = {}
for key, val in d.items():
if isinstance(val, dict):
val = [val]
if isinstance(val, list):
for subidx, subdict in enumerate(val):
deeper = flatten(subdict).items()
out.update({key + f'_{subidx}' + '_' + key2 + f'_{idx}': val2 
for idx, (key2, val2) in enumerate(deeper)})
else:
out[key] = val
return out

输入:

nested = {'a': 1, 
'b': 2, 
'c': {'c1': [{'c11': 1, 'c12': 2, 'c13': 3}, {'c21': 1, 'c22': 2, 'c23': 3}], 
'd1': [{'dd1': 1, 'dd2': 2}, {'dd1': 3, 'dd2': 4}]}, # same keys
'x': [{'xx1': 1, 'xx2': 2}, {'xx1': 3, 'xx2': 4}], # same keys
'y': 2}
<小时 />

输出:

{'a': 1,
'b': 2,
'c_0_c1_0_c11_0_0': 1,
'c_0_c1_0_c12_1_1': 2,
'c_0_c1_0_c13_2_2': 3,
'c_0_c1_1_c21_0_3': 1,
'c_0_c1_1_c22_1_4': 2,
'c_0_c1_1_c23_2_5': 3,
'c_0_d1_0_dd1_0_6': 1,
'c_0_d1_0_dd2_1_7': 2,
'c_0_d1_1_dd1_0_8': 3,
'c_0_d1_1_dd2_1_9': 4,
'x_0_xx1_0': 1,
'x_0_xx2_1': 2,
'x_1_xx1_0': 3,
'x_1_xx2_1': 4,
'y': 2}

最新更新