如何高效确保Address列表中address属性的唯一性?
确保Address列表中address属性唯一性的高效实现方案
问题背景
现有以下C#类定义:
public class Address { public List<AddressElement>? address; public int weight; public int missingComponents; } public class AddressElement { public uint Id { get; set; } public uint ObjectId { get; set; } public Guid ObjectGuid { get; set; } public string Name { get; set; } public byte Level { get; set; } public string UpdateDate { get; set; } // 其他属性 public bool IsActual { get; set; } public bool IsActive { get; set; } }
声明了地址列表:
List<Address> addresses = new();
需求:保证列表中每个Address对象的address属性(List<AddressElement>?类型)具有唯一性,即不存在两个Address的address列表完全相同。
核心思路
由于List<AddressElement>是引用类型,默认比较的是引用地址而非内容,因此需要自定义内容相等判断逻辑,再基于此实现列表的唯一性校验。
步骤1:定义AddressElement的相等规则
首先确定两个AddressElement何时视为相等。从属性来看,ObjectGuid是全局唯一标识,以此作为相等判断依据最可靠:
public class AddressElement { // 原有属性... // 重写Equals判断元素相等 public override bool Equals(object? obj) { return obj is AddressElement element && ObjectGuid.Equals(element.ObjectGuid); } // 重写GetHashCode配合Equals使用 public override int GetHashCode() { return ObjectGuid.GetHashCode(); } }
注:如果需要结合多个属性判断相等(比如Name+Level),可以修改Equals和GetHashCode的逻辑。
步骤2:实现Address的自定义比较器
创建IEqualityComparer<Address>的实现类,用来判断两个Address的address列表是否内容相同:
public class AddressEqualityComparer : IEqualityComparer<Address> { public bool Equals(Address? x, Address? y) { // 处理null场景 if (x == null && y == null) return true; if (x == null || y == null) return false; if (x.address == null && y.address == null) return true; if (x.address == null || y.address == null) return false; // 列表长度不同直接不相等 if (x.address.Count != y.address.Count) return false; // 方案A:严格按顺序比较(地址层级通常有顺序要求,比如省→市→区不能乱) for (int i = 0; i < x.address.Count; i++) { if (!x.address[i].Equals(y.address[i])) return false; } return true; // 方案B:不考虑顺序,只要元素集合相同即相等 // return new HashSet<AddressElement>(x.address).SetEquals(y.address); } public int GetHashCode(Address obj) { if (obj.address == null) return 0; // 组合列表所有元素的哈希值,生成当前Address的哈希码 int hash = 17; foreach (var element in obj.address) { hash = hash * 31 + element.GetHashCode(); } return hash; } }
步骤3:高效维护唯一性列表
方式一:用HashSet自动去重(推荐,效率更高)
HashSet会基于自定义比较器自动判断元素是否重复,添加时直接过滤重复项,查找时间复杂度为O(1):
var addressComparer = new AddressEqualityComparer(); HashSet<Address> uniqueAddresses = new HashSet<Address>(addressComparer); // 添加元素时自动去重 uniqueAddresses.Add(new Address { address = new List<AddressElement> { /* 初始化元素 */ }, weight = 2, missingComponents = 0 }); // 如需转为List List<Address> addresses = uniqueAddresses.ToList();
方式二:手动检查后添加到List
如果必须使用List,在添加前用比较器检查是否已存在(时间复杂度O(n),适合小体量数据):
var addressComparer = new AddressEqualityComparer(); List<Address> addresses = new(); var newAddress = new Address { /* 初始化 */ }; if (!addresses.Any(a => addressComparer.Equals(a, newAddress))) { addresses.Add(newAddress); }
注意事项
- 若地址列表的顺序不影响唯一性,可切换到比较器中的方案B(用
HashSet.SetEquals) - 务必处理
address为null的边界场景,避免空引用异常 - 自定义比较器的方式比直接重写
Address的Equals更灵活,不会影响类在其他场景的默认行为
内容的提问来源于stack exchange,提问作者Александр Попов
相关产品推荐
相关产品推荐

