是否存在等效于Unix命令uniq的Linq实现?Distinct()不符合需求
移除连续重复项的LINQ实现方案
当然可以用LINQ实现这个需求!你提到的Distinct()方法确实是全局去重,会移除所有重复的元素,不管它们是不是连续的——这显然不符合你只移除连续重复项的要求。不过我们可以通过自定义Enumerable扩展方法,或者直接使用Aggregate来实现这个功能。
方法一:自定义扩展方法(推荐,复用性强)
我们可以写一个通用的扩展方法,专门用来过滤序列中的连续重复元素,这样以后任何序列都能直接调用:
public static class EnumerableExtensions { public static IEnumerable<T> RemoveConsecutiveDuplicates<T>(this IEnumerable<T> source) { if (source == null) throw new ArgumentNullException(nameof(source)); using var enumerator = source.GetEnumerator(); if (!enumerator.MoveNext()) yield break; var previous = enumerator.Current; yield return previous; while (enumerator.MoveNext()) { var current = enumerator.Current; if (!EqualityComparer<T>.Default.Equals(current, previous)) { yield return current; previous = current; } } } }
使用示例(匹配你的需求)
int[] input = new [] {1,2,3,3,4,5,5,5,6,6,5,4,4,3,2,1,6}; int[] expected = new [] {1,2,3,4,5,6,5,4,3,2,1,6}; var result = input.RemoveConsecutiveDuplicates().ToArray(); // 此时result和expected完全一致
这个方法的逻辑很清晰:
- 先检查输入序列是否为空,避免空引用异常
- 获取序列的枚举器,先取出第一个元素并返回
- 遍历后续元素,只有当当前元素和前一个元素不相等时,才返回该元素,并更新“前一个元素”的引用
方法二:直接使用Aggregate(无需扩展方法)
如果你不想写扩展方法,也可以用Aggregate来一次性处理:
int[] input = new [] {1,2,3,3,4,5,5,5,6,6,5,4,4,3,2,1,6}; var result = input.Aggregate(new List<int>(), (list, current) => { if (list.Count == 0 || list.Last() != current) list.Add(current); return list; }).ToArray();
这个方式会逐步构建结果列表:每次添加元素前,检查列表最后一个元素是否和当前元素相同,不同才添加。不过相比扩展方法,它需要提前创建列表,对于非常大的序列,内存占用会高一些——扩展方法用的是延迟执行,更高效。
两种方法都能完美满足你的需求,输出结果和你给出的expected数组完全一致。
内容的提问来源于stack exchange,提问作者Rachel Davids
相关产品推荐
相关产品推荐

