在 C# 开发中,处理列表数据对比并提取差异是高频需求,比如对比新旧数据列表找出新增或删除的元素,或者对比两个配置列表找出不同的配置项。下面将介绍多种实现方式,帮助开发者根据实际场景选择合适的方法。

方案一:使用 LINQ 的 Except 方法
LINQ 提供了Except方法,可以直接返回两个序列的差集,也就是第一个列表中存在而第二个列表中不存在的元素,这种方式代码简洁,适合简单场景的差异提取。
示例代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main()
{
// 定义两个原始列表
List<int> list1 = new List<int> { 1, 2, 3, 4, 5 };
List<int> list2 = new List<int> { 3, 4, 5, 6, 7 };
// 找出list1中存在而list2中不存在的元素,存入第三个列表
List<int> diffList = list1.Except(list2).ToList();
Console.WriteLine("差异元素为:");
foreach (var item in diffList)
{
Console.WriteLine(item);
}
}
}
上述代码中,list1.Except(list2)会返回list1有而list2没有的元素集合,这里输出结果为1和2。如果需要同时获取两个列表的双向差异,可以再执行一次list2.Except(list1)并合并结果。
方案二:使用循环遍历对比
如果需要自定义比较规则,或者处理复杂类型的列表,使用循环遍历的方式会更灵活,开发者可以自行控制比较逻辑。
示例代码如下:
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<int> list1 = new List<int> { 1, 2, 3, 4, 5 };
List<int> list2 = new List<int> { 3, 4, 5, 6, 7 };
List<int> diffList = new List<int>();
// 遍历第一个列表,判断元素是否在第二个列表中存在
foreach (var item in list1)
{
if (!list2.Contains(item))
{
diffList.Add(item);
}
}
Console.WriteLine("差异元素为:");
foreach (var item in diffList)
{
Console.WriteLine(item);
}
}
}
这种方式通过Contains方法判断元素是否存在,对于简单值类型列表可以直接使用,如果是自定义引用类型,需要在类型中重写Equals和GetHashCode方法,或者传入自定义的比较器。
方案三:处理自定义类型的列表对比
当列表元素是自定义类时,默认的Except方法会比较对象的引用地址,无法得到预期结果,这时候需要自定义比较逻辑。
首先定义自定义类:
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
}
然后实现IEqualityComparer<Student>接口定义比较规则:
using System;
using System.Collections.Generic;
using System.Linq;
public class StudentComparer : IEqualityComparer<Student>
{
public bool Equals(Student x, Student y)
{
if (x == null || y == null) return false;
return x.Id == y.Id;
}
public int GetHashCode(Student obj)
{
return obj.Id.GetHashCode();
}
}
class Program
{
static void Main()
{
List<Student> list1 = new List<Student>
{
new Student { Id = 1, Name = "张三" },
new Student { Id = 2, Name = "李四" },
new Student { Id = 3, Name = "王五" }
};
List<Student> list2 = new List<Student>
{
new Student { Id = 2, Name = "李四" },
new Student { Id = 3, Name = "王五" },
new Student { Id = 4, Name = "赵六" }
};
// 传入自定义比较器获取差集
List<Student> diffList = list1.Except(list2, new StudentComparer()).ToList();
Console.WriteLine("差异学生信息为:");
foreach (var student in diffList)
{
Console.WriteLine($"Id: {student.Id}, Name: {student.Name}");
}
}
}
上述代码中,通过自定义比较器指定以Id作为学生的唯一标识,最终会输出Id为1的张三,也就是list1中存在而list2中不存在的学生。
不同方案的选择建议
- 如果是简单值类型列表,优先使用
Except方法,代码简洁且可读性强。 - 如果需要自定义比较规则,或者需要同时处理双向差异,可以选择循环遍历的方式。
- 如果是自定义引用类型列表,建议实现
IEqualityComparer接口再配合Except方法使用,兼顾代码简洁性和灵活性。
实际开发中可以根据数据量大小、比较规则复杂度等因素选择合适的实现方式,确保功能正确且性能符合预期。