SequenceEqual有什么好处?

时间:2018-03-30 21:53:05

标签: c# performance linq ienumerable

我在for循环中对SequenceEqual和元素比较进行了比较。

static void Main(string[] args)
    {
        //var myList = new List<short>();
        //var anotherList = new List<short>();
        var myList = new short[2000000];
        var anotherList = new short[2000000];

        for (int i = 0; i < 2000000; i++)
        {
            //myList.Add(5);
            //anotherList.Add(5);
            myList[i] = 5;
            anotherList[i] = 5;
        }

        var watch = System.Diagnostics.Stopwatch.StartNew();
        //for (int i = 0; i < 2000000; i++)
        //{
        //    if (myList[i] != anotherList[i])
        //        break;
        //}
        bool isEqual = myList.SequenceEqual(anotherList);
        watch.Stop();
        var elapsedMs = watch.ElapsedMilliseconds;
        Console.WriteLine(elapsedMs);
        Console.Read();
    }

在myList和anotherList是数组的情况下,直接比较执行4 ms,SequenceEqual执行21ms。当myList和anotherList是列表时,直接比较执行13 ms,SequenceEqual执行30 ms。

如果速度慢得多,是否有使用它的情况?我只能想到一个,它可以保存几行代码。

1 个答案:

答案 0 :(得分:1)

特别针对List进行研究,似乎很慢的问题来自SequenceEqual中使用通用IEnumerator而非List特定的通用实现版本,速度是原来的两倍多。但是,如果您要测试List,也可以直接在for循环中编码,而不是使用枚举。

请注意,对IList的测试速度要慢得多,因为List没有实现IList<T>.operator[],这意味着它会调用IList.operator[]并返回object并导致拳击。

我也是特殊情况Array,因为IList接口比直接访问慢得多,这也是因为拳击。

当然,利用已知类型的高速CountLength,可以使得不等长度比较比SequenceEqual快得多。 OTOH,如果前两个元素不相等,SequenceEqual可能比我的函数更快。

这是我的LocalSequenceEqual

public static bool LocalSequenceEqual<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer = null) {
    if (first is ICollection<TSource> fc && second is ICollection<TSource> sc)
        if (fc.Count != sc.Count)
            return false;

    var cmp = comparer ?? EqualityComparer<TSource>.Default;

    if (first is TSource[] fa && second is TSource[] sa) {
        for (int j1 = 0; j1 < fa.Length; ++j1)
            if (!cmp.Equals(fa[j1], sa[j1]))
                return false;
        return true;
    }

    if (first is List<TSource> fl && second is List<TSource> sl) {
        for (int j1 = 0; j1 < fl.Count; ++j1) {
            if (!cmp.Equals(fl[j1], sl[j1]))
                return false;
        }
        return true;
    }

    using (var e1 = first.GetEnumerator()) {
        using (var e2 = second.GetEnumerator()) {
            while (e1.MoveNext()) {
                if (!(e2.MoveNext() && cmp.Equals(e1.Current, e2.Current)))
                    return false;
            }
            if (e2.MoveNext())
                return false;
        }
    }
    return true;
}