游乐游手机版
首页/编程语言/文章详情

C#怎么使用LINQ Distinct去重 C#如何用LINQ对集合按指定字段去重和自定义比较器【语法】

时间:2026-05-06 07:34
C LINQ Distinct去重方法详解:按字段去重与自定义比较器完整指南 Distinct 默认去重机制:值类型与引用类型的核心差异 在C 中直接对 List 这类自定义引用类型集合调用 Distinct() 方法,通常无法实现按字段内容去重的效果。这是因为默认的 Distinct 操作比较

C# LINQ Distinct去重方法详解:按字段去重与自定义比较器完整指南

C#怎么使用LINQ Distinct去重 C#如何用LINQ对集合按指定字段去重和自定义比较器【语法】

Distinct 默认去重机制:值类型与引用类型的核心差异

在C#中直接对 List 这类自定义引用类型集合调用 .Distinct() 方法,通常无法实现按字段内容去重的效果。这是因为默认的 Distinct 操作比较的是对象的内存引用地址,而非对象内部属性的值。即使两个 Person 实例的 NameAge 属性完全相同,只要它们是不同的对象实例,就会被视为不同元素而保留。

典型问题表现:调用 .Distinct() 后集合元素数量未减少,调试时发现数据重复问题依然存在。

  • 基础值类型(如 intdouble)和 string 可直接使用 .Distinct() 实现去重
  • 自定义类必须显式定义比较逻辑,否则默认基于引用的比较行为无法满足业务需求
  • 字符串虽然是引用类型,但因其重写了 EqualsGetHashCode 方法,故 List.Distinct() 能够正确工作
Distinct方法对引用类型默认执行对象引用去重,需自定义比较逻辑;值类型和已重写Equals的引用类型(如string)可直接使用;单字段去重推荐GroupBy+First组合,多字段去重可采用匿名类型+DistinctBy(.NET 6+)或GroupBy方案,复杂业务场景需实现IEqualityComparer接口。

按单个属性去重:GroupBy + First 组合方案

无需编写比较器代码,也不必创建额外类,这种方法特别适合快速按 IdName 等唯一性字段筛选“首次出现的记录”。

应用示例:从产品列表中提取每个 CategoryId 分类下的第一个 Product 对象

var uniqueByCategory = list
    .GroupBy(x => x.CategoryId)
    .Select(g => g.First())
    .ToList();
  • GroupBy 操作按指定字段分组后,每组至少包含一个元素,使用 First() 选取首个元素,逻辑清晰易懂
  • 性能方面虽略低于 Distinct 配合自定义比较器(需完成分组操作),但开发效率更高且不易出错
  • 若需获取“最新记录”(如按 CreatedTime 降序排列的首条),可将 First() 替换为 OrderByDescending(x => x.CreatedTime).First()

按多个属性组合去重:匿名类型与Distinct的优雅方案

当需要基于 FirstNameLastName 等多个字段的组合进行去重时,利用匿名类型自动实现的相等性比较是最简洁的方案,无需手动编写比较器。

代码示例:去除姓名(姓+名)重复的用户记录

var uniqueByName = users
    .DistinctBy(u => new { u.FirstName, u.LastName })
    .ToList();

⚠️ 重要说明:DistinctBy 是 .NET 6 及以上版本新增的扩展方法(位于 System.Linq 命名空间),旧版本框架需使用 GroupBy 替代实现:

var uniqueByName = users
    .GroupBy(u => new { u.FirstName, u.LastName })
    .Select(g => g.First())
    .ToList();
  • 匿名类型的属性名称和大小写必须完全一致,new { F = u.FirstName }new { FirstName = u.FirstName } 被视为不同的类型
  • 当字段值为 null 时,匿名类型能够正确处理空值比较
  • 此方案不支持动态字段数量(如运行时传入字段名列表),此类场景必须通过自定义 IEqualityComparer 实现

自定义比较器实现:IEqualityComparer 接口的完整控制方案

当业务需要复杂比较逻辑(如忽略大小写、按子字符串匹配、多级优先级判断)或需兼容旧框架(.NET Framework / .NET 5及以下)时,必须通过实现 IEqualityComparer 接口来提供完全可控的比较机制。

示例:实现按 Code 字段忽略大小写的产品去重比较器

public class CodeComparer : IEqualityComparer
{
    public bool Equals(Product x, Product y) =>
        x?.Code?.Equals(y?.Code, StringComparison.OrdinalIgnoreCase) == true;

    public int GetHashCode(Product obj) =>
        obj?.Code?.ToLowerInvariant().GetHashCode() ?? 0;
}

调用方式:

var unique = products.Distinct(new CodeComparer()).ToList();
  • GetHashCode 方法的实现必须与 Equals 方法的逻辑严格一致,否则 Distinct 可能出现漏判或误判
  • 必须显式处理空值(null)情况,避免引发 NullReferenceException 异常
  • 比较器实例应当复用,避免在循环或高频调用路径中重复创建新实例

最易被忽视的关键点:Distinct 操作采用延迟执行模式,但去重的准确性完全依赖于所提供的比较逻辑是否全面覆盖业务场景。例如仅按 Email 字段去重却未处理前后空格或大小写差异,可能导致数据重复问题被隐藏。

来源:https://www.php.cn/faq/2316981.html
上一篇如何在继承 FPDF 的自定义类中正确使用 FPDI 导入 PDF 页面 下一篇C++实现高性能字符串拼接 _ std::ostringstream与reserve对比【干货】
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
Java序列化中ObjectStreamField自定义字段控制详解
编程语言 · 2026-05-11

Java序列化中ObjectStreamField自定义字段控制详解

ObjectStreamField是描述序列化字段的元信息载体。通过声明serialPersistentFields数组并确保字段名、类型、顺序与类定义严格一致,可控制序列化字段。字段不匹配会导致静默反序列化失败。配合writeObject readObject方法可实现动态控制。应避免使用isUnshared、getOffset等底层方法。

实时操作系统RTOS线程调度与Java强实时变量处理对比分析
编程语言 · 2026-05-11

实时操作系统RTOS线程调度与Java强实时变量处理对比分析

实时操作系统(RTOS)通过优先级调度和中断机制确保微秒级确定性,而Java因垃圾回收、同步延迟和内存分配不确定性,难以满足强实时场景的严格时间要求,因此这类系统通常将核心逻辑交由RTOS处理。

Java并行流性能优化CollectorsgroupingByConcurrent方法详解
编程语言 · 2026-05-11

Java并行流性能优化CollectorsgroupingByConcurrent方法详解

Collectors groupingByConcurrent专为无需保持插入顺序、高并发写入的场景设计,能显著提升并行流分组性能。其底层通过所有线程直接写入同一个ConcurrentHashMap,避免了普通groupingBy的合并开销。适用于日志聚合、实时统计等高吞吐任务,但不适用于要求分组顺序的场景。使用时必须搭配并行流,且不支持自定义有序Map。在

循环队列数组实现详解头尾指针操作与取模运算实战指南
编程语言 · 2026-05-11

循环队列数组实现详解头尾指针操作与取模运算实战指南

循环队列通过数组实现,核心在于头尾指针的职责与取模运算。front指向队首,rear指向下一个空位,移动时需取模以确保回环。判空条件为front等于rear,判满则需牺牲一个存储单元。入队和出队操作后需立即取模,避免越界。动态内存管理时需注意分配与释放顺序,防止内存泄漏。

ThinkPHP入口文件配置参数修改与环境变量动态加载指南
编程语言 · 2026-05-11

ThinkPHP入口文件配置参数修改与环境变量动态加载指南

在ThinkPHP框架中动态调整数据库连接等配置参数,是许多开发者实现多环境部署的核心需求。然而,你是否曾遇到这样的困境:在入口文件中修改了配置值,刷新页面后却发现更改并未生效?这通常源于对框架配置加载机制的理解偏差。 本文将深入解析ThinkPHP配置生效的唯一正确路径,帮助你彻底规避“本地测试通