如何比较两个嵌套 dict 并返回差异路径(不依赖 deepdiff)
技术百科
舞姬之光
发布时间:2026-01-26
浏览: 次 递归遍历+路径累积可精准定位差异点,关键在于传入当前路径列表、按类型分治处理、为list中dict提供id字段映射对齐、浮点数启用tolerance与NaN特殊判断,路径统一用list便于后续消费。
用递归遍历 + 路径累积获取差异位置
直接递归比对是最可控的方式,关键在于每层调用时把当前路径(如 ["user", "profile", "age"])作为参数传下去。遇到类型不一致、键缺失或值不同就立即记录路径,不继续深入。这样能精准定位到第一个差异点,也避免构建完整 diff 结构的开销。
注意:路径用 list 而不是 string 累积,方便后续拼接或转 dict.get() 形式;递归出口要覆盖 None、基本类型(str/int/bool)、list、dict 四类常见情况。
- 遇到
dict类型才继续递归,其他类型直接比较 - 若 a 有 key 而 b 没有,记录路径 +
"missing_in_b" - 若 b 有 key 而 a 没有,记录路径 +
"missing_in_a" - 若值都是 dict 但内容不同,继续递归;否则视为
"value_mismatch"
处理 list 差异时不要默认按索引对齐
嵌套 dict 中常含 list(如 {"items": [{"id": 1}, {"id": 2}]}),若简单按索引比对,[{"id": 2}, {"id": 1}] 会被判为全量不一致。实际中更合理的做法是:仅当 list 元素是基本类型(str/int等)时才逐索引比;若元素是 dict,优先按某个唯一字段(如 "id")做映射匹配,再比对子项。
这需要提前约定“可识别字段”,例如传入 id_fields={"items": "id"}。没有

- list 长度不同 → 记录
"list_length_mismatch"并终止该分支 - 元素为 dict 且指定了 id 字段 → 构建
{id_value: dict}映射后比对 - 元素为 dict 但未指定 id 字段 → 按索引比,路径末尾加
[0]、[1]等
避免因浮点精度或 NaN 导致误报
两个 dict 若含浮点数,3.14 == 3.1400000000000001 会返回 False,但业务上可能认为相等。同理,float("nan") == float("nan") 恒为 False,需单独判断。
建议提供 tolerance=1e-9 参数控制数值容差,并在进入比对前用 math.isclose() 替代 ==;对 NaN 统一用 math.isnan() 判断是否均为 NaN。
- 只对
float和int类型启用 tolerance 比较 - 先检查是否都为
NaN,是则视为相等 - 避免对字符串数字(如
"3.14")自动转 float 比较,保持原始类型语义
路径格式统一用 list 表示,支持后续消费
返回的差异路径必须是 list(如 ["data", "users", 0, "name"]),而不是拼好的字符串(如 "data.users[0].name")。前者可直接用于 functools.reduce(dict.get, path, target) 定位值,也便于前端渲染成树形结构或生成 patch 操作。
若需输出可读字符串,应由调用方决定格式(".".join(map(str, path)) 或带括号形式),底层函数不耦合展示逻辑。
- 字典 key 用原值(
"user-id"不转下划线) - list 索引用
int,不用str(0而非"0") - 路径为空 list 表示顶层差异(如类型完全不同)
# 而不是
# 都是
# 均为
# 关键在于
# 下划线
# 递归
# String
# int
# 字符串
# red
# 前端
# map
# 比对
# 遍历
# bool
# Float
# 浮点
# 浮点数
# math
相关栏目:
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
AI推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
SEO优化<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
技术百科<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
谷歌推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
百度推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
网络营销<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
案例网站<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
精选文章<?muma echo $count; ?>
】
相关推荐
- Go 中实现 Python urllib.quot
- Windows如何查看和管理已安装的字体?(字体文
- Win11玩游戏全屏闪退怎么办_Win11全屏优化
- Win10系统映像怎么恢复 Win10使用系统映像
- Win11怎么设置默认邮件客户端 Win11修改M
- 如何用::实现单例模式_php静态方法与作用域操作
- Linux如何安装Golang环境_Linux下G
- Dapper的Execute方法的返回值是什么意思
- c++的mutex和lock_guard如何使用
- 零基础学会Python自动化办公_高效处理Exce
- Win10如何更改任务栏高度_Windows10解
- Windows10如何更改桌面背景_Win10个性
- Win11怎么开启专注模式_Windows11时钟
- Windows蓝屏错误0x0000002C怎么解决
- Win10系统字体模糊怎么办_Windows10高
- 如何使用Golang读取日志文件_Golang b
- c++怎么处理多线程死锁_c++ lock_gua
- Win10怎样清理C盘Steam游戏缓存_Win1
- MAC怎么在照片中添加水印_MAC自带编辑工具文字
- MAC如何快速搜索大文件_MAC磁盘空间分析与冗余
- Python文件操作优化_大文件与流处理解析【教程
- 如何使用Golang操作指针变量_Golang解引
- 如何在 Laravel 中通过嵌套关联关系进行 o
- Win10系统怎么查看网络连接状态_Windows
- Go 语言标准库为何不提供泛型切片的 Contai
- Win11怎么退出高对比度模式_Win11取消反色
- 如何在Golang中使用container/hea
- Python与OpenAI接口集成实战_生成式AI
- Windows蓝屏错误0x0000001E怎么修复
- Win11用户账户控制怎么关_Win11关闭UAC
- c# F# 的 MailboxProcessor
- Windows10怎么查看硬件信息_Windows
- Win11任务栏天气怎么关闭 Win11隐藏天气小
- Windows10如何更改开机密码_Win10登录
- Linux怎么设置磁盘配额_Linux系统Quot
- php打包exe如何加密代码_防反编译保护方法【技
- PHP主流架构怎么集成Redis缓存_配置步骤【方
- 如何在Windows中创建新的用户账户?(标准与管
- Win11声音忽大忽小怎么办 Win11音频增强功
- Win11怎么更改鼠标指针_Windows 11自
- Windows电脑键盘突然失灵怎么办?(驱动与硬件
- Bpmn 2.0的XML文件怎么画流程图
- Python配置文件操作教程_JSONINIYAM
- ACF 教程:如何正确更新嵌套在多层 Group
- Mac如何备份到iCloud_Mac桌面与文稿文件
- php报错怎么查看_定位PHP致命错误与警告的方法
- Win11怎么关闭SmartScreen_禁用Wi
- Windows10无法连接到Internet_Wi
- c++如何使用std::bind绑定函数参数_c+
- 怎么将XML数据可视化 D3.js加载XML

QQ客服