如何检查嵌套字典对象相等性并移除List<Row>中的重复项?
解决Row列表去重与嵌套字典相等性检查问题
一、核心前提:Column类的相等性处理
因为Dictionary<Column, Cell>的键是Column类型,默认的引用相等逻辑会导致键匹配出错,所以必须让Column实现值相等逻辑。假设Column用ColumnId作为唯一标识,重写如下:
public class Column { public int ColumnId { get; set; } // 其他属性... public override bool Equals(object obj) { return obj is Column column && ColumnId == column.ColumnId; } public override int GetHashCode() { return HashCode.Combine(ColumnId); } }
二、嵌套字典的相等性检查逻辑
默认的Dictionary.Equals只比较引用是否相同,要判断两个Dictionary<Column, Cell>内容相等,需满足:
- 两个字典的键集合完全一致(数量相同、每个键都存在于对方字典)
- 每个键对应的
Cell.Value完全相等
方案1:独立的字典比较器
可以封装一个可复用的字典比较器:
public class ColumnCellDictionaryComparer : IEqualityComparer<Dictionary<Column, Cell>> { public bool Equals(Dictionary<Column, Cell> x, Dictionary<Column, Cell> y) { if (x == y) return true; if (x == null || y == null) return false; if (x.Count != y.Count) return false; foreach (var kvp in x) { if (!y.TryGetValue(kvp.Key, out var targetCell)) return false; if (kvp.Value.Value != targetCell.Value) return false; } return true; } public int GetHashCode(Dictionary<Column, Cell> obj) { if (obj == null) return 0; int hash = 17; // 排序保证哈希码不受键的遍历顺序影响 foreach (var kvp in obj.OrderBy(k => k.Key.ColumnId)) { hash = hash * 31 + kvp.Key.GetHashCode(); hash = hash * 31 + (kvp.Value.Value?.GetHashCode() ?? 0); } return hash; } }
三、修正RowEqualityComparer并实现去重
你写的原始比较器存在两个关键问题:
a.Cells.Equals(b.Cells)是引用比较,无法判断内容相等GetHashCode直接返回对象的默认哈希码,导致相同内容的Row无法被Distinct识别
修正后的实现如下:
public class RowEqualityComparer : IEqualityComparer<Row> { private readonly ColumnCellDictionaryComparer _dictComparer = new ColumnCellDictionaryComparer(); public bool Equals(Row a, Row b) { if (a == b) return true; if (a == null || b == null) return false; // 若只需根据Cells的Value去重,忽略Id和Name,就只保留下面的判断 // 若需要同时校验Id/Name,添加对应的判断:a.Id == b.Id && a.Name == b.Name && ... return _dictComparer.Equals(a.Cells, b.Cells); } public int GetHashCode(Row obj) { if (obj == null) return 0; // 与Equals逻辑对应,仅基于Cells生成哈希码 return _dictComparer.GetHashCode(obj.Cells); } }
四、执行去重操作
使用修正后的比较器,直接调用Distinct即可完成去重:
List<Row> originalRows = GetYourRowList(); // 替换为你的原始Row列表 List<Row> uniqueRows = originalRows.Distinct(new RowEqualityComparer()).ToList();
补充说明
- 若
Cell.Value可能为null,当前代码已经兼容(C#中null != null结果为false,符合空值相等的预期) - 如果去重逻辑需要包含
Row.Id或Row.Name,只需在Equals中添加对应判断,并在GetHashCode中合并这些属性的哈希值
内容的提问来源于stack exchange,提问作者Sebastián Rubina
相关产品推荐
相关产品推荐

