如何用Linq获取属性为最大值的所有元素,有无比分组排序更优雅的方案?
问题解答
原生MaxBy确实无法直接实现返回所有最大值元素的需求,它的设计逻辑是当存在多个符合最大值条件的元素时,仅返回序列中第一个匹配的元素。以下是两种比分组排序更优雅、性能更好的实现方案:
方案1:结合最大值属性过滤(实现最简,两次遍历)
这个方案时间复杂度为O(n),远低于原分组排序实现的O(n log n),集合元素量越大性能优势越明显:
// 先取到最大年龄值 int? maxAge = people.MaxBy(p => p.Age)?.Age; // 过滤所有年龄等于最大值的元素 IEnumerable<Person> allOldest = maxAge.HasValue ? people.Where(p => p.Age == maxAge.Value) : Enumerable.Empty<Person>();
方案2:自定义扩展方法(性能最优,一次遍历)
如果要避免两次遍历集合(比如集合是延迟加载的远程数据源、或者元素量极大),可以自己实现通用的返回所有最大值元素的扩展方法:
public static IEnumerable<TSource> MaxAllBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey>? comparer = null) { comparer ??= Comparer<TKey>.Default; using var enumerator = source.GetEnumerator(); if (!enumerator.MoveNext()) yield break; var currentMaxKey = keySelector(enumerator.Current); var maxElements = new List<TSource> { enumerator.Current }; while (enumerator.MoveNext()) { var currentKey = keySelector(enumerator.Current); var compareResult = comparer.Compare(currentKey, currentMaxKey); if (compareResult > 0) { currentMaxKey = currentKey; maxElements.Clear(); maxElements.Add(enumerator.Current); } else if (compareResult == 0) { maxElements.Add(enumerator.Current); } } foreach (var element in maxElements) { yield return element; } }
使用方式非常简洁:
IEnumerable<Person> allOldest = people.MaxAllBy(p => p.Age);
内容的提问来源于stack exchange,提问作者NewTom
相关产品推荐
相关产品推荐

