如何在Python 3.7中高效实现多键分组的JSON转换?
更省心的Python扁平JSON转双层分组结构方案(适配你的需求)
看来你已经用itertools.groupby搞定了基础的转换,但面对更复杂的JSON转换需求,手写循环确实有点费精力——毕竟你更看重开发效率,而且数据集小完全不用纠结性能。刚好你提到Node.js的jsonata,Python里有完美对应工具,还有其他简化方案,我给你详细说说:
首选:用jsonata-python复刻你熟悉的jsonata体验
Python的jsonata包(安装时是jsonata-python)完全照搬了jsonata的语法,用声明式的表达式就能快速完成多层分组转换,不用再写一堆循环拼接字典,后续复杂转换改表达式就行,开发效率拉满。
步骤1:安装依赖
pip install jsonata-python
步骤2:一行表达式搞定转换
替代你原来两个函数的代码,只需要一段jsonata表达式:
import jsonata def mapResearchSubTypeToResolutionCodesToSchema(qryResult): # 编写jsonata转换规则,完全贴合你的分组需求 transform_expr = jsonata.compile(""" // 第一层按rsch_sub_typ_cd分组 $groupBy($, $v => $v.rsch_sub_typ_cd) ~> // 把分组后的字典转成目标列表结构 $map(($resolutions, $rsch_code) => { "researchSubTypeCode": $rsch_code, // 第二层按resl_cd分组,再组装resolutionTypes "resolutionTypes": $groupBy($resolutions, $v => $v.resl_cd) ~> $map(($sub_resolutions, $resl_code) => { "resolutionCode": $resl_code, "resolutionSubTypeCodes": $sub_resolutions.sub_resl_cd }) }) ~> // 包裹成最终的顶层结构 { "researchSubTypeToResolutionCodes": $ } """) return transform_expr.evaluate(qryResult) if __name__ == '__main__': TEST_QRY_DATA = [ {"rsch_sub_typ_cd": None, "resl_cd": 999991, "sub_resl_cd": 99992}, {"rsch_sub_typ_cd": None, "resl_cd": 999991, "sub_resl_cd": 99993}, {"rsch_sub_typ_cd": None, "resl_cd": 999995, "sub_resl_cd": 99996}, {"rsch_sub_typ_cd": 33533, "resl_cd": 33726, "sub_resl_cd": 33730}, {"rsch_sub_typ_cd": 33533, "resl_cd": 33726, "sub_resl_cd": 33731}, {"rsch_sub_typ_cd": 33533, "resl_cd": 33726, "sub_resl_cd": 33732}, {"rsch_sub_typ_cd": 33533, "resl_cd": 33726, "sub_resl_cd": 33774}, {"rsch_sub_typ_cd": 33533, "resl_cd": 33727, "sub_resl_cd": 33730}, {"rsch_sub_typ_cd": 33533, "resl_cd": 33727, "sub_resl_cd": 33731}, {"rsch_sub_typ_cd": 33534, "resl_cd": 33726, "sub_resl_cd": 33730} ] result = mapResearchSubTypeToResolutionCodesToSchema(TEST_QRY_DATA) print(result)
运行这段代码会输出和你预期完全一致的结构,而且后续如果要调整分组规则或者字段映射,只需要修改jsonata表达式,不用动循环逻辑。
备选:用pandas简化代码(不用学新语法)
如果你不想引入新的工具,pandas虽然侧重数据分析,但处理这种分组转换也非常顺手,代码量比原来的itertools写法少很多:
import pandas as pd def mapResearchSubTypeToResolutionCodesToSchema(qryResult): df = pd.DataFrame(qryResult) # 第一步:按两层分组,把sub_resl_cd聚合为列表 grouped = df.groupby(['rsch_sub_typ_cd', 'resl_cd'])['sub_resl_cd'].agg(list).reset_index() # 第二步:按researchSubTypeCode分组,组装resolutionTypes列表 final_df = grouped.groupby('rsch_sub_typ_cd').apply( lambda x: x.rename(columns={ 'resl_cd': 'resolutionCode', 'sub_resl_cd': 'resolutionSubTypeCodes' })[['resolutionCode', 'resolutionSubTypeCodes']].to_dict('records') ).reset_index().rename(columns={ 'rsch_sub_typ_cd': 'researchSubTypeCode', 0: 'resolutionTypes' }) # 组装最终的JSON结构 return {'researchSubTypeToResolutionCodes': final_df.to_dict('records')}
这个方案利用pandas的groupby和agg能力,省去了手动判断字典键是否存在、拼接列表的繁琐步骤,如果你已经熟悉pandas,上手零成本。
方案对比(帮你选合适的)
| 方案 | 开发效率 | 学习成本 | 依赖情况 | 适合场景 |
|---|---|---|---|---|
| jsonata-python | 🌟🌟🌟🌟🌟 | 中等(需要熟悉jsonata语法) | 第三方库 | 复杂JSON转换、有Node.js jsonata经验 |
| pandas | 🌟🌟🌟🌟 | 低(熟悉pandas的话) | 第三方库 | 同时需要数据处理+JSON转换 |
| itertools.groupby | 🌟🌟🌟 | 低 | 内置库 | 不能加额外依赖的场景 |
总结
如果你想复刻jsonata的开发体验,jsonata-python是最佳选择,声明式写法能让你快速搞定各种复杂JSON转换;如果已经在用pandas做数据处理,用pandas的方案也能大幅简化代码。两种方案都比原来的循环写法更省心,完全符合你追求开发效率的需求。
内容的提问来源于stack exchange,提问作者mojoken
相关产品推荐
相关产品推荐

