跳转到主内容
websoft网络软件专家 - 深耕网络技术,打造实用软件!

C#怎么查找List重复元素_C# GroupBy与Where结合去重【极简】

GroupBy是最自然的定位重复项方法,它将相同值元素分组后筛选出数量大于1的组;对引用类型需实现IEqualityComparer或重写Equals/GetHashCode,值类型和记录类型默认支持;可选提取重复值、首次出现的重复项或所有重复原始项,并注意null、NaN及性能优化。 用 GroupBy 找出重复元素本身 直接查哪些元素重复了,不是去重,而是定位重复项——
GroupBy
是最自然的选择。它把相同值的元素归成一组,再用
Where
筛出组内数量大于 1 的那些组。 注意:如果
List
里是引用类型(比如自定义类),默认按引用分组,必须实现
IEqualityComparer
或重写
Equals
+
GetHashCode
,否则同内容不同实例不会被归为一组。 示例(针对
int
):
var duplicates = list.GroupBy(x => x) .Where(g => g.Count() > 1) .Select(g => g.Key) .ToList();
g.Key
是重复的值,不是原始元素对象 如果要保留所有重复出现的原始项(含多次出现的全部副本),改用
SelectMany(g => g)
Count()
在大数据量时有性能开销,可换成
Any()
+
Skip(1).Any()
判断是否至少有两个 用 GroupBy + First/FirstOrDefault 提取“首次出现的重复项” 有时候你不需要所有重复值,只要每个重复值第一次在原列表中出现的那个元素(比如带索引或附加属性的对象)。 这时候不能只靠
g.Key
,得从组里捞出原始项: C知道 CSDN推出的一款AI技术问答工具 下载
var firstOccurrenceOfDuplicates = list.GroupBy(x => x) .Where(g => g.Count() > 1) .Select(g => g.First()) .ToList();
g.First()
拿的是该值在原列表中**最早出现的那个元素**,顺序由原
List
保证 如果元素是匿名类或记录(
record
),默认已实现值相等语义,无需额外配置 对字符串要注意:默认区分大小写;如需忽略大小写,写成
GroupBy(x => x, StringComparer.OrdinalIgnoreCase)
Where 配合 Any 实现“过滤掉重复项”(即去重后保留唯一项) 这不是传统意义的“去重”,而是反向逻辑:只留下那些在整个列表中**仅出现一次**的元素。 常见误区是写成
list.Where(x => list.Count(y => y == x) == 1)
—— 这是 O(n²),小数据还行,上千项就明显卡顿。 更高效的做法是先用
GroupBy
统计频次,再用
Join
或字典缓存映射 极简写法(稍牺牲可读性但实用):
var frequencyMap = list.GroupBy(x => x).ToDictionary(g => g.Key, g => g.Count()); var uniqueItems = list.Where(x => frequencyMap[x] == 1).ToList();
必须确保
x
一定在
frequencyMap
中,否则会抛
KeyNotFoundException
;若不确定,改用
frequencyMap.TryGetValue(x, out int count) && count == 1
这个结果和
list.Distinct()
完全不同:
Distinct()
返回每个值一个代表,而这里是返回所有“没重复过”的原始项 别忘了 null 和 NaN 的特殊行为 当列表含
null
(引用类型)或
double.NaN
时,
GroupBy(x => x)
仍能正常工作,因为
GroupBy
内部用的是
EqualityComparer.Default
,它对
null
和
NaN
有明确定义(
null == null
为 true,
double.NaN.Equals(double.NaN)
也为 true)。 但如果你手动写
Where(x => x == someValue)
做判断,
NaN == NaN
是 false,就会漏掉
NaN
重复项。 安全做法始终依赖
GroupBy
自带的相等比较器 对可空值类型(如
int?
),
null
会被统一归为一组,无需额外处理 自定义比较器中若未显式处理
null
,可能引发
NullReferenceException
实际用的时候,最常踩的坑不是语法,而是没想清楚你要的是“重复的值”“重复的原始项”还是“不重复的原始项”——这三个需求对应完全不同的链式调用结构,差一个
Select
或
SelectMany
就跑偏了。

相关文章