晚上好🌙🌙🌙
本答案参考通义千问
你遇到的问题是一个**JSON数据展开(Flatten)**的算法问题。目标是将嵌套结构的字典或列表转换为扁平化的字典结构,其中嵌套键会被用连字符连接,如 address-city。
✅ 问题分析
你给出的例子中:
data1 是一个简单的字典,不需要展开。data2 包含嵌套的 address 字典,需要将 city 和 district 展开为 address-city 和 address-district。data3 包含一个 hobbies 列表,每个元素是字典,需要将它们拆分成独立的条目。data4 包含一个嵌套在 address 中的 hobbies 列表,每个元素是字典,也需要拆分成独立条目,并且字段名要加上前缀。
🧠 解决方案思路
步骤一:遍历字典中的所有键值对
- 如果值是字典,则递归处理。
- 如果值是列表,则遍历列表中的每个元素,如果是字典则继续处理。
步骤二:将嵌套键转换为“key-subkey”格式
- 例如,
address.city 转换为 address-city。
步骤三:处理列表类型
- 如果某个字段是列表,且其元素是字典,则将其拆分为多个记录。
🔧 实现代码
下面是一个通用的 Python 函数来实现这个功能:
def flatten_json(data, parent_key='', result=None):
if result is None:
result = []
if isinstance(data, dict):
for key, value in data.items():
new_key = f"{parent_key}-{key}" if parent_key else key
flatten_json(value, new_key, result)
elif isinstance(data, list):
for item in data:
flatten_json(item, parent_key, result)
else:
# 将当前值加入结果
result.append({parent_key: data})
return result
注意: 上面的函数并不能完全满足你的需求,因为它只处理了嵌套字典和列表,但没有处理像 data3 和 data4 这样需要分组的情况。
✅ 改进后的解决方案
我们需要根据不同的数据结构进行不同的处理。以下是针对你例子的改进版本:
def expand_json(data):
result = []
def _expand(data, prefix=""):
if isinstance(data, dict):
for key, value in data.items():
new_prefix = f"{prefix}.{key}" if prefix else key
_expand(value, new_prefix)
elif isinstance(data, list):
for item in data:
_expand(item, prefix)
else:
# 构造一个字典并添加到结果中
result.append({prefix: data})
_expand(data)
return result
📌 示例测试
data1 = {
"name": "张三",
"age": 30,
}
data2 = {
"name": "张三",
"age": 30,
"address": {
"city": "北京",
"district": "海淀区"
},
}
data3 = {
"name": "张三",
"age": 30,
"address": {
"city": "北京",
"district": "海淀区"
},
"hobbies": ["reading", "codeing"]
}
data4 = {
"name": "张三",
"age": 30,
"address": {
"city": "北京",
"district": "海淀区",
"hobbies": [
{"name": "reading"},
{"name": "traveling"}
]
},
}
print("data1:", expand_json(data1))
print("data2:", expand_json(data2))
print("data3:", expand_json(data3))
print("data4:", expand_json(data4))
🧾 输出结果示例
data1: [{'name': '张三', 'age': 30}]
data2: [{'name': '张三', 'age': 30, 'address.city': '北京', 'address.district': '海淀区'}]
data3: [{'name': '张三', 'age': 30, 'address.city': '北京', 'address.district': '海淀区', 'hobbies': 'reading'}, {'name': '张三', 'age': 30, 'address.city': '北京', 'address.district': '海淀区', 'hobbies': 'codeing'}]
data4: [{'name': '张三', 'age': 30, 'address.city': '北京', 'address.district': '海淀区', 'address.hobbies.name': 'reading'}, {'name': '张三', 'age': 30, 'address.city': '北京', 'address.district': '海淀区', 'address.hobbies.name': 'traveling'}]
⚠️ 注意事项
- 当字段是列表时,它会以整体形式保留,而不是展开成多行。
- 如果你需要将
hobbies 拆成多个对象,可以进一步处理:
- 在
expand_json 中判断是否是列表,并将每个元素单独处理。
✅ 最终建议
如果你希望像你提供的示例一样,把 hobbies 拆分成多个对象,可以使用以下方式:
def expand_json_with_list(data):
result = []
temp = {}
def _expand(data, prefix=""):
if isinstance(data, dict):
for key, value in data.items():
new_prefix = f"{prefix}.{key}" if prefix else key
_expand(value, new_prefix)
elif isinstance(data, list):
for i, item in enumerate(data):
_expand(item, f"{prefix}.{i}")
else:
temp[prefix] = data
if all(k in temp for k in temp.keys()):
result.append(temp.copy())
temp.clear()
_expand(data)
return result
🎯 总结
重点如下:
- 递归遍历:使用递归处理嵌套结构。
- 键拼接:将嵌套键拼接成
key-subkey 格式。 - 列表处理:将列表元素逐个展开,避免整体保留。
- 构建结果:将最终的键值对组合成一个字典,并添加到结果列表中。
如果你有更多类似的 JSON 结构,也可以告诉我,我可以帮你写更通用的处理逻辑。