C#中如何使用.Except方法移除两列表间的指定重复项?
如何通过
Except方法按OperationId匹配移除列表元素 你的问题核心在于:Except方法默认的比较逻辑不满足需求——它对于自定义引用类型(比如MyObject)默认按对象引用而非OperationId属性值判断是否相等,所以即使两个对象的OperationId相同,也会被判定为不同元素,导致Except没达到预期效果。
下面提供几种正确使用Except实现需求的方法:
方法1:为MyObject重写Equals和GetHashCode
让MyObject基于OperationId定义相等逻辑,这样Except就能正确识别出OperationId相同的元素:
using System; using System.Collections.Generic; using System.Linq; public class Program { public static void Main() { var listA = new List<MyObject>{ new() {OperationId = 123, Mode = "In-Transit", Location = "ATL"}, new() {OperationId = 234, Mode = "Delivered", Location = "PHX"}, new() {OperationId = 345, Mode = "Delivered", Location = "COL"} }; var listB = new List<MyObject>{ new() {OperationId = 123, Mode = "In-Transit", Location = "ATL"} }; var usingExcept = listA.Except(listB); // 输出2,符合预期 Console.WriteLine(usingExcept.Count()); } } public class MyObject { public int OperationId { get; set; } public string Mode { get; set; } public string Location { get; set; } // 重写Equals,基于OperationId判断相等 public override bool Equals(object obj) { return obj is MyObject other && OperationId == other.OperationId; } // 重写GetHashCode,确保相等的对象返回相同哈希值 public override int GetHashCode() { return HashCode.Combine(OperationId); } }
方法2:使用Except的重载,传入自定义IEqualityComparer
如果不想修改MyObject的类定义,可以创建自定义比较器,让Except用该比较器判断元素是否相等:
using System; using System.Collections.Generic; using System.Linq; public class Program { public static void Main() { var listA = new List<MyObject>{ new() {OperationId = 123, Mode = "In-Transit", Location = "ATL"}, new() {OperationId = 234, Mode = "Delivered", Location = "PHX"}, new() {OperationId = 345, Mode = "Delivered", Location = "COL"} }; var listB = new List<MyObject>{ new() {OperationId = 123, Mode = "In-Transit", Location = "ATL"} }; var usingExcept = listA.Except(listB, new MyObjectEqualityComparer()); // 输出2,符合预期 Console.WriteLine(usingExcept.Count()); } } public class MyObject { public int OperationId { get; set; } public string Mode { get; set; } public string Location { get; set; } } // 自定义比较器,基于OperationId比较 public class MyObjectEqualityComparer : IEqualityComparer<MyObject> { public bool Equals(MyObject x, MyObject y) { if (x == null || y == null) return x == y; return x.OperationId == y.OperationId; } public int GetHashCode(MyObject obj) { return obj?.OperationId.GetHashCode() ?? 0; } }
方法3:先提取OperationId集合再筛选
如果仅需基于OperationId过滤,可先获取listB的OperationId集合,再从listA中筛选出不在该集合中的元素,效果和Except一致:
using System; using System.Collections.Generic; using System.Linq; public class Program { public static void Main() { var listA = new List<MyObject>{ new() {OperationId = 123, Mode = "In-Transit", Location = "ATL"}, new() {OperationId = 234, Mode = "Delivered", Location = "PHX"}, new() {OperationId = 345, Mode = "Delivered", Location = "COL"} }; var listB = new List<MyObject>{ new() {OperationId = 123, Mode = "In-Transit", Location = "ATL"} }; var bOperationIds = listB.Select(b => b.OperationId).ToHashSet(); var filteredList = listA.Where(a => !bOperationIds.Contains(a.OperationId)); // 输出2,符合预期 Console.WriteLine(filteredList.Count()); } } public class MyObject { public int OperationId { get; set; } public string Mode { get; set; } public string Location { get; set; } }
补充说明
你原来的RemoveAll能生效,是因为显式指定了用OperationId匹配判断;而Except默认没有这个逻辑,所以需要通过上述方法给Except指定基于OperationId的相等判断规则。
内容的提问来源于stack exchange,提问作者GThree
相关产品推荐
相关产品推荐

