.NET 中怎样快速实现 List 聚集去重? [复制链接]
发表于 2026-2-4 22:00:30 | 显示全部楼层 |阅读模式
媒介

在数据处置惩罚中,去除聚会集的重复元素是一个常见的需求。.NET 6 和 .NET 7 引入了 DistinctBy 方法,这是一个非常实用的新特性,可以方便地根据指定的键对聚集举行去重。
本文将具体先容 DistinctBy 方法的利用,并通过具体的案例来展示其在现实开辟中的应用。
正文

1、DistinctBy 方法

DistinctBy 方法答应我们在 LINQ 查询中根据某个键对聚会集的元素举行去重。
这个方法返回一个新的聚集,此中只包罗根据指定键唯一确定的元素。
方法署名
  1. public static IEnumerable<TSource> DistinctBy<TSource, TKey>(
  2.     this IEnumerable<TSource> source,
  3.     Func<TSource, TKey> keySelector
  4. );
复制代码
2、根本用法

最简朴的用法是在 LINQ 查询中直接调用 DistinctBy 方法,然后处置惩罚去重后的聚集。
阐明
假设我们有一个用户列表,我们想要根据用户名去除重复的用户。
  1. using System.Linq;
  2. class User
  3. {
  4.     public string Name { get; set; }
  5.     public int Age { get; set; }
  6. }
  7. var users = new List<User>
  8. {
  9.     new User { Name = "Alice", Age = 25 },
  10.     new User { Name = "Bob", Age = 32 },
  11.     new User { Name = "Alice", Age = 28 },
  12.     new User { Name = "David", Age = 35 }
  13. };
  14. var distinctUsers = users.DistinctBy(user => user.Name);
  15. foreach (var user in distinctUsers)
  16. {
  17.     Console.WriteLine($"Name: {user.Name}, Age: {user.Age}");
  18. }
复制代码
输出结果:
  1. Name: Alice, Age: 25
  2. Name: Bob, Age: 32
  3. Name: David, Age: 35
复制代码
过滤前后元素照旧保持原有的序次,我们可以查察源码。
源码
  1. private static IEnumerable<TSource> DistinctByIterator<TSource, TKey>(IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey>? comparer)
  2. {
  3.     using IEnumerator<TSource> enumerator = source.GetEnumerator();
  4.     if (enumerator.MoveNext())
  5.     {
  6.         var set = new HashSet<TKey>(DefaultInternalSetCapacity, comparer);
  7.         do
  8.         {
  9.             TSource element = enumerator.Current;
  10.             if (set.Add(keySelector(element)))
  11.             {
  12.                 yield return element;
  13.             }
  14.         }
  15.         while (enumerator.MoveNext());
  16.     }
  17. }
复制代码
通过查察源码,可以看到是利用了 HashSet 去重,元素序次并未被打乱。
在处置惩罚聚集时,我们常常须要去除重复的元素,同时保持原有的序次。
利用 HashSet 可以高效地实现这一目的。
起首将指定的键实验添加到 HashSet 中,如果添加乐成,阐明该键没有重复;
如果添加失败,阐明已经存在类似的键,此元素将被过滤掉。
3、复杂用法

DistinctBy 方法可以用于更复杂的去重逻辑,比方根据多个属性举行去重。
阐明
假设我们有一个订单列表,我们想要根据客户名称和订单金额去除重复的订单。
  1. class Order
  2. {
  3.     public int OrderId { get; set; }
  4.     public string CustomerName { get; set; }
  5.     public decimal Amount { get; set; }
  6. }
  7. var orders = new List<Order>
  8. {
  9.     new Order { OrderId = 1, CustomerName = "Alice", Amount = 100.0m },
  10.     new Order { OrderId = 2, CustomerName = "Bob", Amount = 150.0m },
  11.     new Order { OrderId = 3, CustomerName = "Alice", Amount = 100.0m },
  12.     new Order { OrderId = 4, CustomerName = "Charlie", Amount = 120.0m },
  13.     new Order { OrderId = 5, CustomerName = "Bob", Amount = 150.0m }
  14. };
  15. var distinctOrders = orders.DistinctBy(order => (order.CustomerName, order.Amount));
  16. foreach (var order in distinctOrders)
  17. {
  18.     Console.WriteLine($"Order ID: {order.OrderId}, Customer: {order.CustomerName}, Amount: {order.Amount}");
  19. }
复制代码
输出结果:
  1. Order ID: 1, Customer: Alice, Amount: 100.0
  2. Order ID: 2, Customer: Bob, Amount: 150.0
  3. Order ID: 4, Customer: Charlie, Amount: 120.0
复制代码
4、性能思量

DistinctBy 方法在内部利用哈希表来跟踪已经出现的键,因此在大多数情况下性能非常好。但在处置惩罚非常大的数据集时,仍然须要留意内存利用情况。
阐明
假设我们有一个包罗数百万条纪录的大聚集,我们须要根据某个键举行去重。
  1. var largeCollection = Enumerable.Range(1, 10000000).Select(i => new { Id = i, Value = i % 1000 });
  2. var distinctLargeCollection = largeCollection.DistinctBy(item => item.Value);
  3. Console.WriteLine($"Distinct count: {distinctLargeCollection.Count()}");
复制代码
5、异步 LINQ 查询中的利用

DistinctBy 方法也可以在异步 LINQ 查询中利用,连合 IAsyncEnumerable 范例,处置惩罚大量数据时更加高效。
阐明
假设我们有一个异步方法返回一个用户列表,我们想要根据用户名去除重复的用户。
  1. using System.Net.Http.Json;
  2. public async IAsyncEnumerable<User> GetUsersAsync()
  3. {
  4.     var response = await httpClient.GetAsync("https://api.example.com/users");
  5.     var usersJson = await response.Content.ReadAsStringAsync();
  6.    
  7.     // 使用Json序列化工具解析用户列表
  8.     var users = JsonSerializer.Deserialize<List<User>>(usersJson);
  9.    
  10.     foreach (var user in users)
  11.     {
  12.         yield return user;
  13.     }
  14. }
  15. // 使用异步LINQ查询
  16. var distinctUsers = await GetUsersAsync().DistinctByAsync(user => user.Name).ToListAsync();
  17. foreach (var user in distinctUsers)
  18. {
  19.     Console.WriteLine($"Name: {user.Name}, Age: {user.Age}");
  20. }
复制代码
总结

DistinctBy 方法是 .NET 6 和 .NET 7 中 LINQ 的一个非常实用的新特性。我们在 LINQ 查询中根据指定的键对聚集举行去重,简化了代码并进步了开辟服从。
渴望本文能资助各人更好地明确和利用 .NET 6 和 .NET 7 中 LINQ 的 DistinctBy 方法,从而在项目中发挥更大的作用。
末了


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表