如何使用Linq从List<MyClass>中按Address去重并保留最小signal实例?
问题描述
我定义了MyClass类并将其实例存入List<MyClass>集合中。当集合中存在Address相同的MyClass实例时,我希望仅保留其中signal值最小的那个实例。
示例代码如下:
class MyClass { public int Id { get; set; } public int signal { get; set; } public int Address { get; set; } } static List<MyClass> myClasses = new List<MyClass>(); static void Main(string[] args) { MyClass myClass = new MyClass(); myClass.Id = 1; myClass.signal = 2; myClass.Address = 1234; myClasses.Add(myClass); myClass.Id = 1; myClass.signal = 4; myClass.Address = 5678; myClasses.Add(myClass); myClass.Id = 2; myClass.signal = 3; myClass.Address = 1234; myClasses.Add(myClass); myClass.Id = 2; myClass.signal = 3; myClass.Address = 5678; myClasses.Add(myClass); }
期望处理后myClasses中仅保留以下实例:
myClass.Id = 1; myClass.signal = 2; myClass.Address = 1234;
myClass.Id = 2; myClass.signal = 3; myClass.Address = 5678;
我认为可以用Linq解决该问题,请问具体该如何实现?
解决方案
没错,LINQ完全可以轻松搞定这个需求!核心思路就是先按Address把实例分组,然后在每个分组里筛选出signal值最小的那个实例。这里有两种实用的实现方式,你可以根据自己的.NET版本选择:
方式一:通用分组排序取最小(兼容所有.NET版本)
这种方式不管你用的是哪个.NET版本都能跑通,逻辑也很直观:
using System.Linq; // 执行筛选逻辑 var filteredList = myClasses .GroupBy(mc => mc.Address) // 把相同Address的实例归为一组 .Select(group => group.OrderBy(mc => mc.signal).First() // 对每组按signal从小到大排序,取第一个(也就是最小的) ) .ToList(); // 如果需要替换原集合,直接赋值就行 myClasses = filteredList;
方式二:用MinBy简化操作(.NET 6+专属)
如果你用的是.NET 6或更高版本,微软新增了MinBy方法,可以直接在分组里找到signal最小的实例,省去排序步骤,代码更简洁,性能也更好:
using System.Linq; var filteredList = myClasses .GroupBy(mc => mc.Address) .Select(group => group.MinBy(mc => mc.signal)) // 直接获取分组中signal最小的实例 .ToList(); myClasses = filteredList;
额外说明
- 针对你示例里的情况:Address=5678的两个实例signal都是3,两种方式都会保留分组中最先出现的那个实例,刚好符合你的期望结果。
MinBy的效率更高,因为它不需要对整个分组排序,只需要遍历一次就能找到最小值对应的实例,数据量大的时候差异会更明显。
内容的提问来源于stack exchange,提问作者playground
相关产品推荐
相关产品推荐

