比较 C# 中的数组
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/713341/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Comparing arrays in C#
提问by
I am trying to compare two arrays with each other. I tried this code and got the following errors.
我正在尝试将两个数组相互比较。我尝试了此代码并收到以下错误。
static bool ArraysEqual(Array a1, Array a2)
{
if (a1 == a2)
return true;
if (a1 == null || a2 == null)
return false;
if (a1.Length != a2.Length)
return false;
IList list1 = a1, list2 = a2; //error CS0305: Using the generic type 'System.Collections.Generic.IList<T>' requires '1' type arguments
for (int i = 0; i < a1.Length; i++)
{
if (!Object.Equals(list1[i], list2[i])) //error CS0021: Cannot apply indexing with [] to an expression of type 'IList'(x2)
return false;
}
return true;
}
Why do I get that error? I went for a low-tech solution and did this which works fine, but I need to copy/paste it several times for each type.
为什么我会收到那个错误?我选择了一个低技术的解决方案,并且这样做效果很好,但我需要为每种类型复制/粘贴几次。
static bool ArraysEqual(byte[] a1, byte[] a2)
{
if (a1 == a2)
return true;
if (a1 == null || a2 == null)
return false;
if (a1.Length != a2.Length)
return false;
for (int i = 0; i < a1.Length; i++)
{
if (a1[i] != a2[i])
return false;
}
return true;
}
回答by Marc Gravell
"Why do i get that error?" - probably, you don't have "using System.Collections;
" at the top of the file - only "using System.Collections.Generic;
" - however, generics are probably safer - see below:
“为什么我会收到那个错误?” - 可能,您using System.Collections;
在文件顶部没有“ ” - 只有“ using System.Collections.Generic;
” - 但是,泛型可能更安全 - 见下文:
static bool ArraysEqual<T>(T[] a1, T[] a2)
{
if (ReferenceEquals(a1,a2))
return true;
if (a1 == null || a2 == null)
return false;
if (a1.Length != a2.Length)
return false;
EqualityComparer<T> comparer = EqualityComparer<T>.Default;
for (int i = 0; i < a1.Length; i++)
{
if (!comparer.Equals(a1[i], a2[i])) return false;
}
return true;
}
回答by Noldorin
Providing that you have LINQ available and don't care too much about performance, the easiest thing is the following:
假设您有可用的 LINQ 并且不太关心性能,最简单的事情如下:
var arraysAreEqual = Enumerable.SequenceEqual(a1, a2);
In fact, it's probably worth checking with Reflectoror ILSpywhat the SequenceEqual
methods actually does, since it may well optimise for the special case of array values anyway!
事实上,可能值得用Reflector或ILSpy检查这些SequenceEqual
方法的实际作用,因为无论如何它都可以针对数组值的特殊情况进行优化!
回答by Imi
SequenceEqual can be faster. Namely in the case where almost all of the time, both arrays have indeed the same length and are not the same object.
SequenceEqual 可以更快。即在几乎所有时间的情况下,两个数组确实具有相同的长度并且不是相同的对象。
It's still not the same functionality as the OP's function, as it won't silently compare null values.
它仍然与 OP 的功能不同,因为它不会默默地比较空值。
回答by Valentin Kuzub
Recommending SequenceEqual is ok, but thinking that it may ever be faster than usual for(;;) loop is too naive.
推荐 SequenceEqual 是可以的,但认为它可能比通常的 for(;;) 循环更快是太天真了。
Here is the reflected code:
这是反射的代码:
public static bool SequenceEqual<TSource>(this IEnumerable<TSource> first,
IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
{
if (comparer == null)
{
comparer = EqualityComparer<TSource>.Default;
}
if (first == null)
{
throw Error.ArgumentNull("first");
}
if (second == null)
{
throw Error.ArgumentNull("second");
}
using (IEnumerator<TSource> enumerator = first.GetEnumerator())
using (IEnumerator<TSource> enumerator2 = second.GetEnumerator())
{
while (enumerator.MoveNext())
{
if (!enumerator2.MoveNext() || !comparer.Equals(enumerator.Current, enumerator2.Current))
{
return false;
}
}
if (enumerator2.MoveNext())
{
return false;
}
}
return true;
}
As you can see it uses 2 enumerators and fires numerous method calls which seriously slow everything down. Also it doesn't check length at all, so in bad cases it can be ridiculously slower.
如您所见,它使用 2 个枚举器并触发大量方法调用,这会严重减慢一切速度。而且它根本不检查长度,所以在糟糕的情况下它可能会慢得离谱。
Compare moving two iterators with beautiful
比较漂亮的移动两个迭代器
if (a1[i] != a2[i])
and you will know what I mean about performance.
你会知道我对性能的意思。
It can be used in cases where performance is really not so critical, maybe in unit test code, or in cases of some short list in rarely called methods.
它可以用于性能真的不是那么重要的情况,可能是在单元测试代码中,或者在很少调用的方法中的一些短列表的情况下。
回答by Yuliia Ashomok
For .NET 4.0and higher you can compare elements in array or tuples via using StructuralComparisonstype:
对于.NET 4.0及更高版本,您可以使用StructuralComparisons类型比较数组或元组中的元素:
object[] a1 = { "string", 123, true };
object[] a2 = { "string", 123, true };
Console.WriteLine (a1 == a2); // False (because arrays is reference types)
Console.WriteLine (a1.Equals (a2)); // False (because arrays is reference types)
IStructuralEquatable se1 = a1;
//Next returns True
Console.WriteLine (se1.Equals (a2, StructuralComparisons.StructuralEqualityComparer));
回答by Xavier
I know this is an old topic, but I think it is still relevant, and would like to share an implementation of an array comparison method which I feel strikes the right balance between performance and elegance.
我知道这是一个古老的话题,但我认为它仍然相关,并且想分享一个数组比较方法的实现,我觉得它在性能和优雅之间取得了适当的平衡。
static bool CollectionEquals<T>(ICollection<T> a, ICollection<T> b, IEqualityComparer<T> comparer = null)
{
return ReferenceEquals(a, b) || a != null && b != null && a.Count == b.Count && a.SequenceEqual(b, comparer);
}
The idea here is to check for all of the early out conditions first, then fall back on SequenceEqual
. It also avoids doing extra branching and instead relies on boolean short-circuit to avoid unecessary execution. I also feel it looks clean and is easy to understand.
这里的想法是首先检查所有提前退出条件,然后再回到SequenceEqual
. 它还避免进行额外的分支,而是依靠布尔短路来避免不必要的执行。我也觉得它看起来很干净,很容易理解。
Also, by using ICollection
for the parameters, it will work with more than just arrays.
此外,通过ICollection
用于参数,它不仅可以处理数组。