C#在Distinct()中使用IEqualityComparer<T>

基本语法

csharp 复制代码
var uniqueItems = sourceCollection.Distinct(new YourCustomComparer());

其中YourCustomComparer()是你实现的IEqualityComparer<T> 类的实例。


完整示例

沿用之前定义的Person类和PersonNameComparer:

csharp 复制代码
using System;
using System.Collections.Generic;
using System.Linq;
public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public override string ToString()
    {
        return $"Person(Name='{Name}', Age={Age})";
    }
}
// 根据 Name(忽略大小写)判断是否相等
public class PersonNameComparer : IEqualityComparer<Person>
{
    public bool Equals(Person x, Persony)
    {
        if (x == null && y == null) return true;
        if (x == null || y == null) return false;
        return string.Equals(x.Name, y.Name, StringComparison.OrdinalIgnoreCase);
    }
    public int GetHashCode(Person obj)
    {
        if (obj == null) return 0;
        return obj.Name?.GetHashCode(StringComparison.OrdinalIgnoreCase) ?? 0;
    }
}
使用Distinct(IEqualityComparer<T>)
csharp 复制代码
class Program
{
    static void Main()
    {
        // 创建一个包含"重复"姓名(但大小写不同)的列表
        var people = new List<Person>
        {
            new Person { Name = "Alice", Age = 30 },
            new Person { Name = "alice", Age = 25 }, // 名字相同,大小写不同
            new Person { Name = "Bob", Age = 35 },
            new Person { Name = "BOB", Age = 40 },   // 名字相同,大小写不同
            new Person { Name = "Charlie", Age = 28 }
        };
        Console.WriteLine("原始列表:");
        foreach (var person in people)
        {
            Console.WriteLine(person);
        }
        // 使用自定义比较器进行去重
        var distinctPeople = people.Distinct(new PersonNameComparer());
        Console.WriteLine("\n去重后(根据名字忽略大小写):");
        foreach (var person in distinctPeople)
        {
            Console.WriteLine(person);
        }
    }
}
输出结果
markdown 复制代码
原始列表:
Person(Name='Alice', Age=30)
Person(Name='alice', Age=25)
Person(Name='Bob', Age=35)
Person(Name='BOB', Age=40)
Person(Name='Charlie', Age=28)
去重后(根据名字忽略大小写):
Person(Name='Alice', Age=30)
Person(Name='Bob', Age=35)
Person(Name='Charlie', Age=28)

关键点说明

  1. 选择第一个 :Distinct() 在遇到"相等"的元素时,通常会保留第一次出现的那个元素。在上面的例子中,"Alice" 被保留,而后面的 "alice" 被去除了。
  2. 必须提供比较器 :如果你的对象没有合适的Equals和GetHashCode重写,或者你需要不同于默认行为的比较逻辑(如忽略大小写、比较特定属性等),就必须传入一个IEqualityComparer<T>实例。否则,Distinct() 会使用引用相等性(对于引用类型)或值相等性(对于值类型),这可能不是你想要的结果。
  3. 链式调用 :Distinct()返回的是一个IEnumerable<T>,所以你可以继续进行其他 LINQ 操作:
csharp 复制代码
var result = people
    .Distinct(new PersonNameComparer())
    .Where(p => p.Age > 30)
    .OrderBy(p => p.Name);

更简洁的写法(如果比较逻辑简单)

如果只是简单的字符串忽略大小写去重,可以直接用内置的StringComparer:

csharp 复制代码
var names = new List<string> { "Alice", "alice", "Bob", "BOB" };
var distinctNames = names.Distinct(StringComparer.OrdinalIgnoreCase);

但对于复杂对象,自定义IEqualityComparer<T> 是最清晰和可复用的方式。

总之,在Distinct()中使用IEqualityComparer<T>就是将其实例作为参数传递给Distinct() 方法,从而精确控制"什么是重复"的定义。

相关推荐
xyouyuweizhu9 分钟前
字节流与字符流:Java IO 的两条主线该怎么选
java·开发语言·python
多弗朗皮卡丘1 小时前
C++的IO流
开发语言·c++·io流·文件io流
骑着蜗牛撵大象3271 小时前
AI Agent 工程化开发实战(三):用 StateGraph 给智能体搭一条可回放的状态流水线
java·开发语言·jvm·ai·状态管理·langgraph·stategraph
itmigrate1 小时前
Rust 里的所有权误区:不是不写 clone 就叫高性能
开发语言·后端·rust
Brilliantwxx1 小时前
【Linux】 文件访问与路径解析:目录、文件名、dentry、路径缓冲与 dcache 全解析
linux·运维·服务器·开发语言·spring
摇滚侠2 小时前
《On Java 中文版 基础卷》阅读笔记 初始化和清理 08
java·开发语言·笔记
xiangyun612 小时前
C++ 手撕 shared_ptr:引用计数与控制块到底长什么样?
开发语言·c++·算法·面试·stl
XiYang-DING2 小时前
P4009.和为K的子数组个数 & P5522.异或和为 k 的子数组个数
java·开发语言
jaysee-sjc2 小时前
【苍穹外卖】Day12:工作台数据看板与 Excel 报表导出
java·开发语言·数据库·spring boot·spring·微信·excel
w_zero_one2 小时前
算法--桶思想
java·开发语言·算法