gpt4 book ai didi

python - 在 Python 中展平通用 JSON 字典列表或列表

转载 作者:太空宇宙 更新时间:2023-11-03 15:15:22 25 4
gpt4 key购买 nike

我有一组任意的 JSON 数据,这些数据已在 Python 中解析为字典列表和不同深度的列表。我需要能够将其“扁平化”为字典列表。示例如下:

源数据示例 1

[{u'industry': [
{u'id': u'112', u'name': u'A'},
{u'id': u'132', u'name': u'B'},
{u'id': u'110', u'name': u'C'},
],
u'name': u'materials'},
{u'industry': {u'id': u'210', u'name': u'A'},
u'name': u'conglomerates'}
]

期望的结果示例 1

[{u'name':u'materials', u'industry_id':u'112', u'industry_name':u'A'},
{u'name':u'materials', u'industry_id':u'132', u'industry_name':u'B'},
{u'name':u'materials', u'industry_id':u'110', u'industry_name':u'C'},
{u'name':u'conglomerates', u'industry_id':u'210', u'industry_name':u'A'},
]

对于这个简单的例子来说这已经足够简单了,但我并不总是有这种精确的字典列表结构,还有一层额外的字典列表。在某些情况下,我可能有额外的嵌套需要遵循相同的方法。因此,我认为我需要递归,但我似乎无法让它发挥作用。

提议的方法论

1) 对于每个字典列表,在每个键前加上一个提供父键名称的“路径”。在上面的示例中,“industry”是包含字典列表的键,因此列表中的每个子字典都添加了“industry”。

2) 向列表中的每个字典添加“父”项 - 在这种情况下,“名称”和“行业”是顶级字典列表中的项,因此添加了“名称”键/值“行业”中的每一项。

我可以想象一些场景,您在“父”项中有多个字典列表,甚至是字典的字典,并且将这些子树中的每一个应用于子字典列表是行不通的。因此,我假设“父”项始终是简单的键/值对。

再举一个例子来说明需要处理的数据结构中的潜在变化。

源数据示例 2

[{u'industry': [
{u'id': u'112', u'name': u'A'},
{u'id': u'132', u'name': u'B'},
{u'id': u'110', u'name': u'C', u'company': [
{u'id':'500', u'symbol':'X'},
{u'id':'502', u'symbol':'Y'},
{u'id':'504', u'symbol':'Z'},
]
},
],
u'name': u'materials'},
{u'industry': {u'id': u'210', u'name': u'A'},
u'name': u'conglomerates'}
]

期望的结果示例 2

[{u'name':u'materials', u'industry_id':u'112', u'industry_name':u'A'},
{u'name':u'materials', u'industry_id':u'132', u'industry_name':u'B'},
{u'name':u'materials', u'industry_id':u'110', u'industry_name':u'C',
u'company_id':'500', u'company_symbol':'X'},
{u'name':u'materials', u'industry_id':u'110', u'industry_name':u'C',
u'company_id':'502', u'company_symbol':'Y'},
{u'name':u'materials', u'industry_id':u'110', u'industry_name':u'C',
u'company_id':'504', u'company_symbol':'Z'},
{u'name':u'conglomerates', u'industry_id':u'210', u'industry_name':u'A'},
]

我查看了其他几个示例,但似乎找不到适用于这些示例的示例。

有什么建议或指点吗?我花了一些时间尝试构建一个递归函数来处理这个问题,但在很多小时后都没有运气......

更新一次失败的尝试

def _flatten(sub_tree, flattened=[], path="", parent_dict={}, child_dict={}):
if type(sub_tree) is list:
for i in sub_tree:
flattened.append(_flatten(i,
flattened=flattened,
path=path,
parent_dict=parent_dict,
child_dict=child_dict
)
)
return flattened
elif type(sub_tree) is dict:
lists = {}
new_parent_dict = {}
new_child_dict = {}
for key, value in sub_tree.items():
new_path = path + '_' + key
if type(value) is dict:
for key2, value2 in value.items():
new_path2 = new_path + '_' + key2
new_parent_dict[new_path2] = value2
elif type(value) is unicode:
new_parent_dict[key] = value
elif type(value) is list:
lists[new_path] = value
new_parent_dict.update(parent_dict)
for key, value in lists.items():
for i in value:
flattened.append(_flatten(i,
flattened=flattened,
path=key,
parent_dict=new_parent_dict,
)
)
return flattened

我得到的结果是“无”对象的 231x231 矩阵 - 显然我遇到了递归失控的麻烦。

我已经尝试了一些额外的“从头开始”尝试,但都以类似的失败模式失败了。

最佳答案

好的。我的解决方案有两个功能。第一个是 splitObj,负责将对象拆分为平面数据和稍后需要递归的子列表或子对象。第二,flatten,实际上迭代对象列表,进行递归调用并负责为每次迭代重建最终对象。

def splitObj (obj, prefix = None):
'''
Split the object, returning a 3-tuple with the flat object, optionally
followed by the key for the subobjects and a list of those subobjects.
'''
# copy the object, optionally add the prefix before each key
new = obj.copy() if prefix is None else { '{}_{}'.format(prefix, k): v for k, v in obj.items() }

# try to find the key holding the subobject or a list of subobjects
for k, v in new.items():
# list of subobjects
if isinstance(v, list):
del new[k]
return new, k, v
# or just one subobject
elif isinstance(v, dict):
del new[k]
return new, k, [v]
return new, None, None

def flatten (data, prefix = None):
'''
Flatten the data, optionally with each key prefixed.
'''
# iterate all items
for item in data:
# split the object
flat, key, subs = splitObj(item, prefix)

# just return fully flat objects
if key is None:
yield flat
continue

# otherwise recursively flatten the subobjects
for sub in flatten(subs, key):
sub.update(flat)
yield sub

请注意,这并不能完全产生您想要的输出。这样做的原因是你的输出实际上是不一致的。在第二个示例中,对于行业中嵌套公司的情况,嵌套在输出中不可见。因此,我的输出将生成 industry_company_idindustry_company_symbol:

>>> ex1 = [{u'industry': [{u'id': u'112', u'name': u'A'},
{u'id': u'132', u'name': u'B'},
{u'id': u'110', u'name': u'C'}],
u'name': u'materials'},
{u'industry': {u'id': u'210', u'name': u'A'}, u'name': u'conglomerates'}]
>>> ex2 = [{u'industry': [{u'id': u'112', u'name': u'A'},
{u'id': u'132', u'name': u'B'},
{u'company': [{u'id': '500', u'symbol': 'X'},
{u'id': '502', u'symbol': 'Y'},
{u'id': '504', u'symbol': 'Z'}],
u'id': u'110',
u'name': u'C'}],
u'name': u'materials'},
{u'industry': {u'id': u'210', u'name': u'A'}, u'name': u'conglomerates'}]

>>> pprint(list(flatten(ex1)))
[{'industry_id': u'112', 'industry_name': u'A', u'name': u'materials'},
{'industry_id': u'132', 'industry_name': u'B', u'name': u'materials'},
{'industry_id': u'110', 'industry_name': u'C', u'name': u'materials'},
{'industry_id': u'210', 'industry_name': u'A', u'name': u'conglomerates'}]
>>> pprint(list(flatten(ex2)))
[{'industry_id': u'112', 'industry_name': u'A', u'name': u'materials'},
{'industry_id': u'132', 'industry_name': u'B', u'name': u'materials'},
{'industry_company_id': '500',
'industry_company_symbol': 'X',
'industry_id': u'110',
'industry_name': u'C',
u'name': u'materials'},
{'industry_company_id': '502',
'industry_company_symbol': 'Y',
'industry_id': u'110',
'industry_name': u'C',
u'name': u'materials'},
{'industry_company_id': '504',
'industry_company_symbol': 'Z',
'industry_id': u'110',
'industry_name': u'C',
u'name': u'materials'},
{'industry_id': u'210', 'industry_name': u'A', u'name': u'conglomerates'}]

关于python - 在 Python 中展平通用 JSON 字典列表或列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21512957/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com