是否有内置的方法来比较IEnumerable (按其元素)?

我想比较给定类型的元素列表,看看哪个列表 “更大”。

new BuiltInComparer<IEnumerable>().Compare( new[] {3,2,3}, new[] {1,2,3}) 

……会返回1

 new BuiltInComparer<IEnumerable>().Compare( new[] {1,2,3}, new[] {1,2,4}) 

……会返回-1等

有没有这样的内置比较器?

我不认为框架中有任何内容 – 正如Eric所说,你还没有提供比较标准。 如果你的意思是“以自然的方式比较元素,并假设’缺失的’元素小于任何现有的元素”(即如果它们在可能的情况下相等则更长的序列击败更短的子序列)那么这样的事情会做它:

 public int SequenceCompare(IEnumerable source1, IEnumerable source2) { // TODO: Parameter validation :) // You could add an overload with this as a parameter IComparer elementComparer = Comparer.Default; using (IEnumerator iterator1 = source1.GetEnumerator()) using (IEnumerator iterator2 = source2.GetEnumerator()) { while (true) { bool next1 = iterator1.MoveNext(); bool next2 = iterator2.MoveNext(); if (!next1 && !next2) // Both sequences finished { return 0; } if (!next1) // Only the first sequence has finished { return -1; } if (!next2) // Only the second sequence has finished { return 1; } // Both are still going, compare current elements int comparison = elementComparer.Compare(iterator1.Current, iterator2.Current); // If elements are non-equal, we're done if (comparison != 0) { return comparison; } } } } 

更精致的版本:

 public static class EnumerableExtensions { ///  /// Performs lexical comparison of 2 IEnumerable collections holding elements of type T. ///  /// Type of collection elements. /// The first collection to compare. /// The second collection to compare. /// A signed integer that indicates the relative values of a and b: /// Less than zero: first is less than second; /// Zero: first is equal to second; /// Greater than zero: first is greater than second. ///  ///  /// Can be called as either static method: EnumerableExtensions.Compare(a, b) or /// extension method: a.Compare(b). ///  public static int Compare(this IEnumerable first, IEnumerable second) { // If one of collection objects is null, use the default Comparer class // (null is considered to be less than any other object) if (first == null || second == null) return Comparer.Default.Compare(first, second); var elementComparer = Comparer.Default; int compareResult; using (var firstEnum = first.GetEnumerator()) using (var secondEnum = second.GetEnumerator()) { do { bool gotFirst = firstEnum.MoveNext(); bool gotSecond = secondEnum.MoveNext(); // Reached the end of collections => assume equal if (!gotFirst && !gotSecond) return 0; // Different sizes => treat collection of larger size as "greater" if (gotFirst != gotSecond) return gotFirst ? 1 : -1; compareResult = elementComparer.Compare(firstEnum.Current, secondEnum.Current); } while (compareResult == 0); } return compareResult; } } 

如果您使用的是.NET 4(并且它听起来不像您),我认为您可以使用Enumerable.Zip做一些聪明的事情。 就像是:

 var r = x.Zip(y, comparer.Compare).FirstOrDefault(c => c != 0); 

虽然我现在还不能看到如何有效地处理较短的一个与较长的一个相同的情况,就其而言。

编辑 :如果你只是比较数组(或者不关心测量你的集合两次),那么我认为你可以简单地添加:

 if (r == 0) { r = int.Compare(x.Count(), y.Count()); } 

您甚至可以将它们组合为:

 var r = x.Zip(y, comparer.Compare) .Concat(new [] { int.Compare(x.Count(), y.Count()) }) .FirstOrDefault(c => c != 0) 

(如果你使用的是.NET 3.5,那么添加一个Zip扩展方法,因为它很容易编写并且在所有地方都非常有用!我不知道为什么它不包含在最初的Linq版本中。)

没有内置的比较器。 但是,这是经常出现的要求。 我在SequenceComparer文章中详细介绍了这个主题; 这是一个简化的实现:

 public class SequenceComparer : Comparer> { private readonly IComparer _elementComparer; public SequenceComparer(IComparer elementComparer = null) { _elementComparer = elementComparer ?? Comparer.Default; } public override int Compare(IEnumerable x, IEnumerable y) { // Get enumerators to iterate over both sequences in sync. using (IEnumerator xEnumerator = x.GetEnumerator()) using (IEnumerator yEnumerator = y.GetEnumerator()) { // Advance both enumerators to their next element, // until at least one passes the end of its sequence. bool xMove, yMove; while ((xMove = xEnumerator.MoveNext()) && (yMove = yEnumerator.MoveNext())) { // Compare the current pair of elements across the two sequences, // seeking element inequality. int elementComparison = _elementComparer.Compare(xEnumerator.Current, yEnumerator.Current); if (elementComparison != 0) return elementComparison; } // Determine the relative length of the two sequences based on the final values of xMove and yMove. return xMove.CompareTo(yMove); } } }