引言
在 C# 开发中,我们经常需要对两个集合进行对比,找出差异项,比如:
- A 中有而 B 中没有的数据;
- A 和 B 中相同 ID 但属性不同的数据;
- 或者反过来找出 B 中有而 A 没有的数据……
本文将带你从基础到进阶,系统地掌握这些实用的集合操作技巧,并通过一个真实场景来演示如何高效实现这类对比逻辑。
🎯 一、问题背景
假设你有两个 List<TaskInfoEntity_GuiBao>
类型的集合 A 和 B:
public class TaskInfoEntity_GuiBao
{
public string BatchNo { get; set; }
public string TaskStatus { get; set; }
}
你需要找出:
- 集合 A 中存在但集合 B 中不存在的项(即
BatchNo
不在 B 中); - 或者虽然存在,但
TaskStatus
不一致的项。
✅ 二、解决方案:使用 LINQ + Dictionary 提高效率
方法一:构建字典快速查找
我们先将集合 B 转换为以 BatchNo
为 Key 的字典,这样后续查询时可以做到 O(1) 时间复杂度。
var bDict = B.ToDictionary(b => b.BatchNo, b => b.TaskStatus);
方法二:筛选符合条件的数据
然后遍历集合 A,筛选出满足条件的项:
var result = A.Where(a =>
{
if (!bDict.TryGetValue(a.BatchNo, out var statusInB))
{
// BatchNo 不存在于 B 中
return true;
}
// 存在于 B 中,但 TaskStatus 不一致
return a.TaskStatus != statusInB;
}).ToList();
这段代码清晰易懂,且性能优异,非常适合处理大量数据。
🔁 三、拓展:双向对比 —— 找出 A 和 B 的所有差异项
如果你还需要找出“集合 B 中有但集合 A 中没有”的数据,就需要对 A 和 B 做双向对比。
实现思路:
我们可以分别对 A 和 B 进行两次筛选,合并结果即可。
var aDict = A.ToDictionary(a => a.BatchNo, a => a.TaskStatus);
var bDict = B.ToDictionary(b => b.BatchNo, b => b.TaskStatus);
var diffA = A.Where(a =>
!bDict.TryGetValue(a.BatchNo, out var statusInB) || a.TaskStatus != statusInB
).Select(a => new { Source = "A", Item = a });
var diffB = B.Where(b =>
!aDict.TryGetValue(b.BatchNo, out var statusInA) || b.TaskStatus != statusInA
).Select(b => new { Source = "B", Item = b });
var allDifferences = diffA.Concat(diffB).ToList();
使用匿名对象记录来源,方便后续分析。
📌 四、进阶:自定义比较器实现深度对比
如果你希望使用 .Except()
、.Union()
等 LINQ 方法,可以实现一个自定义的 IEqualityComparer<T>
。
public class TaskComparer : IEqualityComparer<TaskInfoEntity_GuiBao>
{
public bool Equals(TaskInfoEntity_GuiBao x, TaskInfoEntity_GuiBao y)
{
if (x == null || y == null) return false;
return x.BatchNo == y.BatchNo && x.TaskStatus == y.TaskStatus;
}
public int GetHashCode(TaskInfoEntity_GuiBao obj)
{
return obj?.BatchNo?.GetHashCode() ?? 0;
}
}
使用示例:
var differences = A.Except(B, new TaskComparer()).ToList();
这种方式适用于更复杂的对象比较逻辑,也更容易复用。
🧪 五、实战案例:日志同步系统中的差异检测
场景描述:
你正在开发一个任务日志同步系统,每天会从外部接口拉取最新任务状态(集合 B),并与本地缓存的任务状态(集合 A)做对比,只更新那些发生变化或新增的任务。
解决方案:
你可以使用上面提到的方法,找出需要插入或更新的任务列表,从而避免全量同步,提高性能。
🧠 六、知识点总结
技术点 | 描述 |
---|---|
ToDictionary | 快速构建索引,提高查找效率 |
TryGetValue | 安全获取值并判断是否存在 |
Where + 条件判断 | 灵活筛选符合条件的元素 |
IEqualityComparer<T> | 自定义比较逻辑,用于 Except , Union 等方法 |
匿名类型 | 临时记录来源信息,便于调试 |
双向对比 | 同时找出 A 和 B 中不一致的数据 |
💡 七、结语
集合操作是 C# 编程中非常核心的部分,掌握好这些技巧不仅可以提升代码质量,还能显著提高程序性能。特别是在处理大数据集、日志分析、数据同步等业务场景时,合理使用集合对比技巧能事半功倍。
记住一句话:“不是你不会写,而是你不知道怎么优雅地写。”
📚 附录:完整示例代码
// 定义实体类
public class TaskInfoEntity_GuiBao
{
public string BatchNo { get; set; }
public string TaskStatus { get; set; }
}
// 主函数或调用处
var result = A.Where(a =>
{
if (!bDict.TryGetValue(a.BatchNo, out var statusInB))
{
return true;
}
return a.TaskStatus != statusInB;
}).ToList();