惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

F
Fortinet All Blogs
有赞技术团队
有赞技术团队
量子位
N
Netflix TechBlog - Medium
博客园 - 叶小钗
博客园 - 三生石上(FineUI控件)
Google DeepMind News
Google DeepMind News
aimingoo的专栏
aimingoo的专栏
GbyAI
GbyAI
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Blog — PlanetScale
Blog — PlanetScale
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
月光博客
月光博客
Martin Fowler
Martin Fowler
Y
Y Combinator Blog
宝玉的分享
宝玉的分享
博客园 - 司徒正美
云风的 BLOG
云风的 BLOG
V
Visual Studio Blog
V
V2EX
IT之家
IT之家
L
LangChain Blog
大猫的无限游戏
大猫的无限游戏
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

博客园 - 小码编匠

C# + ViewFaceCore 快速实现高精度人脸识别 推荐 .NET 8.0 开源项目伪微服务框架 C# 不依赖 OpenCV 的图像处理算法:滤波、锐化与边缘检测 一款轻量级 WinForm 开源控件库,让老界面秒变高颜值 别再说 WinForm 做的工业软件丑了!这些开源库让它颜值拉满、交互流畅 .NET 8 微服务框架长什么样?集成 AI 智能体、多租户、自动调度与实时通信 基于 JSON 配置的 .NET 桌面应用自动更新方案 开源 .NET 工作流引擎 + 可视化设计,轻松搞定 OA/CRM/ERP 开发 Visual Studio 2026 上手体验,AI 懂你、界面清爽、协作无缝 告别人工干预!C# 轻量级上位机自动联动 MES 与视觉检测 WPF 如何支撑一个灵活的流程图编辑器? .NET 8.0 + Vue 企业级在线培训系统(开源、免费、支持多种主流数据库) 一行代码快速开发 AntdUI 风格的 WinForm 通用后台框架 一个拒绝过度设计的 .NET 快速开发框架:开箱即用,专注"干活" 告别手动更新!WinForm 应用轻松集成自动升级功能 (HHUpdateApp) .NET 9 + React 开发的企业级后台权限管理系统,文档齐全,轻松上手 .NET 8 gRPC 实现高效100G大文件断点续传工具 .NET 开源工业视觉系统 OpenIVS 快速搭建自动化检测平台 .NET 8 开发的跨平台多商户第三方支付SDK
.NET 中如何快速实现 List 集合去重?
小码编匠 · 2026-02-04 · via 博客园 - 小码编匠

前言

在数据处理中,去除集合中的重复元素是一个常见的需求。.NET 6 和 .NET 7 引入了 DistinctBy 方法,这是一个非常实用的新特性,可以方便地根据指定的键对集合进行去重。

本文将详细介绍 DistinctBy 方法的使用,并通过具体的案例来展示其在实际开发中的应用。

正文

1、DistinctBy 方法

DistinctBy 方法允许我们在 LINQ 查询中根据某个键对集合中的元素进行去重。

这个方法返回一个新的集合,其中只包含根据指定键唯一确定的元素。

方法签名

public static IEnumerable<TSource> DistinctBy<TSource, TKey>(
    this IEnumerable<TSource> source,
    Func<TSource, TKey> keySelector
);

2、基本用法

最简单的用法是在 LINQ 查询中直接调用 DistinctBy 方法,然后处理去重后的集合。

说明

假设我们有一个用户列表,我们想要根据用户名去除重复的用户。

using System.Linq;
​
class User
{
    public string Name { get; set; }
    public int Age { get; set; }
}
​
var users = new List<User>
{
    new User { Name = "Alice", Age = 25 },
    new User { Name = "Bob", Age = 32 },
    new User { Name = "Alice", Age = 28 },
    new User { Name = "David", Age = 35 }
};
​
var distinctUsers = users.DistinctBy(user => user.Name);
​
foreach (var user in distinctUsers)
{
    Console.WriteLine($"Name: {user.Name}, Age: {user.Age}");
}

输出结果:

Name: Alice, Age: 25
Name: Bob, Age: 32
Name: David, Age: 35

过滤前后元素还是保持原有的顺序,我们可以查看源码。

源码

private static IEnumerable<TSource> DistinctByIterator<TSource, TKey>(IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey>? comparer)
{
    using IEnumerator<TSource> enumerator = source.GetEnumerator();
​
    if (enumerator.MoveNext())
    {
        var set = new HashSet<TKey>(DefaultInternalSetCapacity, comparer);
        do
        {
            TSource element = enumerator.Current;
            if (set.Add(keySelector(element)))
            {
                yield return element;
            }
        }
        while (enumerator.MoveNext());
    }
}

通过查看源码,可以看到是利用了 HashSet 去重,元素顺序并未被打乱。

在处理集合时,我们经常需要去除重复的元素,同时保持原有的顺序。

使用 HashSet 可以高效地实现这一目标。

首先将指定的键尝试添加到 HashSet 中,如果添加成功,说明该键没有重复;

如果添加失败,说明已经存在相同的键,此元素将被过滤掉。

3、复杂用法

DistinctBy 方法可以用于更复杂的去重逻辑,例如根据多个属性进行去重。

说明

假设我们有一个订单列表,我们想要根据客户名称和订单金额去除重复的订单。

class Order
{
    public int OrderId { get; set; }
    public string CustomerName { get; set; }
    public decimal Amount { get; set; }
}
​
var orders = new List<Order>
{
    new Order { OrderId = 1, CustomerName = "Alice", Amount = 100.0m },
    new Order { OrderId = 2, CustomerName = "Bob", Amount = 150.0m },
    new Order { OrderId = 3, CustomerName = "Alice", Amount = 100.0m },
    new Order { OrderId = 4, CustomerName = "Charlie", Amount = 120.0m },
    new Order { OrderId = 5, CustomerName = "Bob", Amount = 150.0m }
};
​
var distinctOrders = orders.DistinctBy(order => (order.CustomerName, order.Amount));
​
foreach (var order in distinctOrders)
{
    Console.WriteLine($"Order ID: {order.OrderId}, Customer: {order.CustomerName}, Amount: {order.Amount}");
}

输出结果:

Order ID: 1, Customer: Alice, Amount: 100.0
Order ID: 2, Customer: Bob, Amount: 150.0
Order ID: 4, Customer: Charlie, Amount: 120.0

4、性能考虑

DistinctBy 方法在内部使用哈希表来跟踪已经出现的键,因此在大多数情况下性能非常好。但在处理非常大的数据集时,仍然需要注意内存使用情况。

说明

假设我们有一个包含数百万条记录的大集合,我们需要根据某个键进行去重。

var largeCollection = Enumerable.Range(1, 10000000).Select(i => new { Id = i, Value = i % 1000 });
var distinctLargeCollection = largeCollection.DistinctBy(item => item.Value);
Console.WriteLine($"Distinct count: {distinctLargeCollection.Count()}");

5、异步 LINQ 查询中的使用

DistinctBy 方法也可以在异步 LINQ 查询中使用,结合 IAsyncEnumerable<T> 类型,处理大量数据时更加高效。

说明

假设我们有一个异步方法返回一个用户列表,我们想要根据用户名去除重复的用户。

using System.Net.Http.Json;
​
public async IAsyncEnumerable<User> GetUsersAsync()
{
    var response = await httpClient.GetAsync("https://api.example.com/users");
    var usersJson = await response.Content.ReadAsStringAsync();
    
    // 使用Json序列化工具解析用户列表
    var users = JsonSerializer.Deserialize<List<User>>(usersJson);
    
    foreach (var user in users)
    {
        yield return user;
    }
}
​
// 使用异步LINQ查询
var distinctUsers = await GetUsersAsync().DistinctByAsync(user => user.Name).ToListAsync();
​
foreach (var user in distinctUsers)
{
    Console.WriteLine($"Name: {user.Name}, Age: {user.Age}");
}

总结

DistinctBy 方法是 .NET 6 和 .NET 7 中 LINQ 的一个非常实用的新特性。我们在 LINQ 查询中根据指定的键对集合进行去重,简化了代码并提高了开发效率。

希望本文能帮助大家更好地理解和利用 .NET 6 和 .NET 7 中 LINQ 的 DistinctBy 方法,从而在项目中发挥更大的作用。

最后

如果你觉得这篇文章对你有帮助,不妨点个赞支持一下!你的支持是我继续分享知识的动力。如果有任何疑问或需要进一步的帮助,欢迎随时留言。也可以加入微信公众号 [DotNet技术匠] 社区,与其他热爱技术的同行一起交流心得,共同成长!