嵌套HashSet是否为合适数据模型?去重失效问题求助
问题分析与解决方案
一、嵌套HashSet是否适合当前场景?
是否合适取决于你的业务需求:
- 如果每个列值组(
columns中的子集合)需要无序存储且内部不允许重复的ColumnValues实例,那么HashSet<ColumnValues>是合理的选择; - 如果列值组需要保留固定顺序(比如和原始数据的列顺序一致),则应该将内部的
HashSet替换为List<ColumnValues>,再配合对应顺序的相等性判断逻辑。
但你当前遇到的去重失败问题,核心原因是HashSet的默认相等性判断是引用比较,而非内容比较,且你的自定义比较器未正确实现集合内容的相等逻辑。
二、解决重复元素问题的具体步骤
1. 修正ColumnValues的相等性逻辑
你当前的Equals和GetHashCode存在冗余判断(column字段和Column属性是同一值),简化后才能保证单个ColumnValues实例的相等性判断正确:
public class ColumnValues { private readonly string _column; private readonly string _value; public ColumnValues(string col, string val) { _column = col; _value = val; } public string Column => _column; public string Value => _value; public override bool Equals(object obj) { return obj is ColumnValues other && _column == other._column && _value == other._value; } public override int GetHashCode() { return HashCode.Combine(_column, _value); } }
2. 实现正确的HashSet<ColumnValues>比较器
你的自定义比较器直接调用HashSet.Equals(),而该方法默认是引用相等判断,完全没起到内容比较的作用。正确的逻辑应该是用SetEquals()判断集合内容是否一致,同时基于集合元素的哈希码生成集合的哈希值:
public class HashSetColumnValuesComparer : IEqualityComparer<HashSet<ColumnValues>> { public bool Equals(HashSet<ColumnValues> x, HashSet<ColumnValues> y) { if (ReferenceEquals(x, y)) return true; if (x == null || y == null) return false; // HashSet.SetEquals()会判断两个集合是否包含完全相同的元素(无序) return x.SetEquals(y); } public int GetHashCode(HashSet<ColumnValues> obj) { if (obj == null) return 0; // 基于集合内所有元素的哈希码组合生成集合的哈希值 int hash = 17; foreach (var cv in obj) { hash = hash * 31 + cv.GetHashCode(); } return hash; } }
3. 使用修正后的比较器去重
调用Distinct时传入正确的比较器即可实现基于内容的去重:
var dataModels = new List<DataModel>(); GatherColumns(code.Syntax); var comparer = new HashSetColumnValuesComparer(); dataModels.ForEach(dataModel => dataModel.Columns = dataModel.Columns.Distinct(comparer).ToList() ); return dataModels;
三、优化建议
如果希望从源头避免重复,可以直接将DataModel中的Columns字段定义为HashSet<HashSet<ColumnValues>>,并在初始化时传入上述自定义比较器,这样添加元素时会自动去重,无需事后调用Distinct。
内容的提问来源于stack exchange,提问作者Fares
相关产品推荐
相关产品推荐

