问题描述
我在for循环中对SequenceEqual和元素比较进行了比较.
I did a comparison between SequenceEqual and element comparison in for loop.
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.
In the case when myList and anotherList are arrays, the direct comparison executes for 4 ms, SequenceEqual executes for 21ms. When myList and anotherList are lists, the direct comparison executes for 13 ms, SequenceEqual for 30 ms.
如果速度慢得多,是否有使用时会有益的情况?我只能想到其中之一,它节省了几行代码.
If it is so much slower, are there cases when it would be beneficial to use? I can only think of one, that it saves several lines of code.
推荐答案
更具体地研究List
,似乎很多放缓源于SequenceEqual
中使用通用IEnumerator
的通用实现. List
特定版本的速度,是两倍多的速度.但是,如果仍然要测试List
,则最好直接在for
循环中进行编码,而不要使用枚举.
Looking into especially List
s more specifically, it seems a lot of slow down comes from the generic implementation in SequenceEqual
using the generic IEnumerator
instead of the List
specific version, which is more than twice as fast. However, if you are going to test for List
anyway, might as well code in the for
loop directly instead of using enumeration.
请注意,对IList
的测试要慢得多,因为List
没有实现IList<T>.operator[]
,这意味着它将调用IList.operator[]
并返回object
并导致装箱.
Note that testing for IList
is a lot slower, because List
doesn't implement IList<T>.operator[]
which means it calls IList.operator[]
which returns object
and causes boxing.
我还特例Array
,因为IList
界面比直接访问要慢得多,这也是由于装箱造成的.
I also special case Array
s as the IList
interface is much slower than direct access, again due to boxing.
当然,利用已知类型的高速Count
或Length
可以使不相等的长度比较比SequenceEqual
快得多. OTOH,如果前两个元素不相等,则SequenceEqual
可能比我的函数要快.
Of course, taking advantage of the high speed Count
or Length
available for known types makes unequal length comparisons tremendously faster than SequenceEqual
. OTOH, if the first two elements are unequal, SequenceEqual
can be faster than my function.
这是我的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;
}
这篇关于SequenceEqual有什么好处?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!