代码之家  ›  专栏  ›  技术社区  ›  Cristian Diaconescu

有没有一种内置的方法来比较IEnumerable<T>(按元素)?

  •  2
  • Cristian Diaconescu  · 技术社区  · 16 年前

    我想比较一个给定类型的元素列表,看看 列表

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

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

    …将返回-1等

    4 回复  |  直到 16 年前
        1
  •  11
  •   Jon Skeet    14 年前

    我认为框架中没有内置任何东西——正如Eric所说,您还没有提供比较标准。如果您的意思是“以自然的方式比较元素,并假设一个‘缺失’元素比任何现有元素都小”(即,如果它们在可能的情况下相等,则较长的序列比较短的子序列好),那么类似这样的操作就可以做到:

    public int SequenceCompare<T>(IEnumerable<T> source1, IEnumerable<T> source2)
    {
        // TODO: Parameter validation :)
        // You could add an overload with this as a parameter
        IComparer<T> elementComparer = Comparer<T>.Default;       
        using (IEnumerator<T> iterator1 = source1.GetEnumerator())
        using (IEnumerator<T> 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;
                }
            }
        }
    }
    
        2
  •  4
  •   Crulex    13 年前

    更精致的版本:

    public static class EnumerableExtensions
    {
        /// <summary>
        /// Performs lexical comparison of 2 IEnumerable collections holding elements of type T. 
        /// </summary>
        /// <typeparam name="T">Type of collection elements.</typeparam>
        /// <param name="first">The first collection to compare.</param>
        /// <param name="second">The second collection to compare.</param>
        /// <returns>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.
        /// </returns>
        /// <remarks>
        /// Can be called as either static method: EnumerableExtensions.Compare(a, b) or
        /// extension method: a.Compare(b).
        /// </remarks>
        public static int Compare<T>(this IEnumerable<T> first, IEnumerable<T> 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<T>.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;
        }
    }
    
        3
  •  2
  •   Ken    16 年前

    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)
    

    (如果您使用的是.NET3.5,那么就添加一个Zip扩展方法,因为它很容易编写,而且非常有用!我不知道为什么它没有包含在最初的Linq版本中。)

        4
  •  0
  •   Douglas    10 年前

    没有内置比较器。然而,这是一个经常出现的要求。在我的报告中,我已经详细地讨论了这个话题 SequenceComparer<T> 第条;下面是一个简化的实现:

    public class SequenceComparer<TElement> : Comparer<IEnumerable<TElement>>
    {
        private readonly IComparer<TElement> _elementComparer;
    
        public SequenceComparer(IComparer<TElement> elementComparer = null)
        {
            _elementComparer = elementComparer ?? Comparer<TElement>.Default;
        }
    
        public override int Compare(IEnumerable<TElement> x, IEnumerable<TElement> y)
        {
            // Get enumerators to iterate over both sequences in sync.
            using (IEnumerator<TElement> xEnumerator = x.GetEnumerator())
            using (IEnumerator<TElement> 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);
            }
        }
    }
    
    推荐文章