如何用LINQ对IEnumerable序列集合跨序列排序?是否需自定义IComparer?
好问题!这种针对多个序列本身而非序列内部元素排序的需求,我之前也碰到过。LINQ本身没有直接开箱即用的方法,但我们可以用更简洁的方式实现,不用完全从头写自定义IComparer类,下面给你两种实用方案:
方法1:用Comparer.Create快速构建序列比较器(通用IEnumerable场景)
这个方案适用于所有实现IEnumerable<T>的序列类型,比如数组、List、自定义枚举器等,逻辑和字符串的字典序一致:逐个比较对应位置的元素,元素不同则返回结果;如果前面元素都相同,短序列排在前面。
代码示例:
// 定义待排序的序列集合 var sequences = new[] { new[] {"Z", "B", "C"}, new[] {"A", "B", "C"}, new[] {"B", "B", "C"} }; // 执行排序 var sortedSequences = sequences.OrderBy(seq => seq, Comparer<IEnumerable<string>>.Create((a, b) => { using var enumA = a.GetEnumerator(); using var enumB = b.GetEnumerator(); while (true) { bool hasNextA = enumA.MoveNext(); bool hasNextB = enumB.MoveNext(); if (!hasNextA && !hasNextB) return 0; // 两个序列完全相等 if (!hasNextA) return -1; // A序列更短,排在前面 if (!hasNextB) return 1; // B序列更短,A排在后面 // 比较当前位置的元素(这里用字符串默认比较逻辑) int elementCompare = string.Compare(enumA.Current, enumB.Current, StringComparison.Ordinal); if (elementCompare != 0) return elementCompare; } })).ToArray();
方法2:针对数组/List等索引可访问的序列简化逻辑
如果你的序列都是数组、List这类实现IList<T>的类型,可以直接通过索引访问元素,省去枚举器的使用,代码更简洁:
var sortedSequences = sequences.OrderBy(seq => seq, Comparer<string[]>.Create((a, b) => { int minLength = Math.Min(a.Length, b.Length); for (int i = 0; i < minLength; i++) { int compareResult = string.Compare(a[i], b[i], StringComparison.Ordinal); if (compareResult != 0) return compareResult; } // 前面元素都相同,比较长度 return a.Length.CompareTo(b.Length); })).ToArray();
拓展:封装泛型比较器复用
如果你的项目中经常需要对不同类型的序列做类似排序,可以封装一个通用的泛型比较器,只要元素类型实现IComparable<T>就能用:
public static class SequenceComparer { public static IComparer<IEnumerable<T>> Create<T>() where T : IComparable<T> { return Comparer<IEnumerable<T>>.Create((a, b) => { using var enumA = a.GetEnumerator(); using var enumB = b.GetEnumerator(); while (true) { bool hasA = enumA.MoveNext(); bool hasB = enumB.MoveNext(); if (!hasA && !hasB) return 0; if (!hasA) return -1; if (!hasB) return 1; int cmp = enumA.Current.CompareTo(enumB.Current); if (cmp != 0) return cmp; } }); } }
使用的时候就非常简洁:
var sortedSequences = sequences.OrderBy(seq => seq, SequenceComparer.Create<string>()).ToArray();
总的来说,.NET没有内置的序列比较器(毕竟序列的排序规则可能有多种,比如是先比长度还是先比元素),但借助Comparer.Create可以快速实现符合你需求的字典序比较逻辑,配合LINQ的OrderBy就能轻松完成多个序列的排序,比手动实现IComparer<IEnumerable<T>>接口要高效很多。
内容的提问来源于stack exchange,提问作者andleer
相关产品推荐
相关产品推荐

