C#如何忽略集合元素顺序比对引用类型对象集合的相等性
C# 实现忽略数组元素顺序的Basket类相等性比对
要实现两个Basket实例忽略items数组顺序的相等性判断,需要先解决Item类型的值相等性判断,再处理集合的无序比较逻辑,以下是两种常用实现方案:
方案1:修改原类实现IEquatable接口(推荐)
步骤1:实现Item的值相等性判断
默认引用类型的Equals方法比较的是内存地址,需要重写Equals和GetHashCode方法,让属性值相同的Item被判定为相等:
public class Item : IEquatable<Item> { public string name { get; set; } public double price { get; set; } public bool Equals(Item other) { if (other == null) return false; // 若对浮点数精度有要求,可改为 Math.Abs(price - other.price) < 1e-6 做容差判断 return name == other.name && price == other.price; } public override bool Equals(object obj) => Equals(obj as Item); public override int GetHashCode() { // C# 低版本可手动组合哈希码,这里用官方提供的HashCode工具类 return HashCode.Combine(name, price); } }
步骤2:实现Basket的无序相等性判断
public class Basket : IEquatable<Basket> { public Item[] items; public bool Equals(Basket other) { if (other == null) return false; // 长度不一致直接返回不等 if (items.Length != other.items.Length) return false; // 方法A:按统一规则排序后顺序比较,逻辑简单直观,适合元素量不大的场景 return items.OrderBy(i => i.name).ThenBy(i => i.price) .SequenceEqual(other.items.OrderBy(i => i.name).ThenBy(i => i.price)); // 方法B:分组统计元素数量,时间复杂度更低,适合元素量大的场景 // var group1 = items.GroupBy(i => i).ToDictionary(g => g.Key, g => g.Count()); // var group2 = other.items.GroupBy(i => i).ToDictionary(g => g.Key, g => g.Count()); // return group1.Count == group2.Count && group1.All(kv => group2.TryGetValue(kv.Key, out var count) && count == kv.Value); } public override bool Equals(object obj) => Equals(obj as Basket); // 如果需要将Basket作为哈希表的键,可实现该方法 public override int GetHashCode() { var hash = new HashCode(); foreach (var item in items.OrderBy(i => i.name).ThenBy(i => i.price)) { hash.Add(item); } return hash.ToHashCode(); } }
调用示例
直接调用Equals方法即可得到预期结果:
bool result = basket1.Equals(basket2); // 返回True
方案2:自定义比较器(无需修改原类)
如果不能修改Item和Basket的原有定义,可以单独实现比较器完成判断:
public class ItemComparer : IEqualityComparer<Item> { public bool Equals(Item x, Item y) { if (x == null && y == null) return true; if (x == null || y == null) return false; return x.name == y.name && x.price == y.price; } public int GetHashCode(Item obj) { return HashCode.Combine(obj.name, obj.price); } }
封装比较方法:
public static bool BasketEquals(Basket b1, Basket b2) { if (b1 == null || b2 == null) return b1 == b2; if (b1.items.Length != b2.items.Length) return false; var comparer = new ItemComparer(); return b1.items.OrderBy(i => i.name).ThenBy(i => i.price) .SequenceEqual(b2.items.OrderBy(i => i.name).ThenBy(i => i.price), comparer); }
调用示例
bool result = BasketEquals(basket1, basket2); // 返回True
注意事项
- 不要直接使用
HashSet<Item>.SetEquals做比较,该方法会自动去重,若两个Basket的相同Item数量不一致会出现误判 - 若price是经过浮点运算得到的值,建议增加容差判断避免精度问题导致的相等性判断失败
内容的提问来源于stack exchange,提问作者O'Neil Tomlinson
相关产品推荐
相关产品推荐

