【发布时间】:2010-12-12 18:46:33
【问题描述】:
如何在 C# 中比较两个数组?
我使用下面的代码,但它的结果是假的。我期待它是真的。
Array.Equals(childe1,grandFatherNode);
【问题讨论】:
-
你能给我们举个例子吗?
如何在 C# 中比较两个数组?
我使用下面的代码,但它的结果是假的。我期待它是真的。
Array.Equals(childe1,grandFatherNode);
【问题讨论】:
您可以使用 System.Linq 中的 Enumerable.SequenceEqual() 来比较数组中的内容
bool isEqual = Enumerable.SequenceEqual(target1, target2);
【讨论】:
Enumerable.SequenceEqual(x, y) 和 x.SequenceEqual(y) 的行为方式相同:如果第一个或第二个集合为空,它们会抛出 ArgumentNullException。看看implementation on Reference Source。
x.SequenceEqual 是一种扩展方法,因此它与调用Enumerable.SequenceEqual 完全相同。因此,无论您以哪种方式编写调用,有关空输入的行为都是相同的
您正在比较 对象引用,它们并不相同。您需要比较数组内容。
一个选项是遍历数组元素并为每个元素调用Equals()。请记住,如果数组元素不是同一个对象引用,则需要覆盖 Equals() 方法。
另一种方法是使用这种泛型方法来比较两个泛型数组:
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;
var comparer = EqualityComparer<T>.Default;
for (int i = 0; i < a1.Length; i++)
{
if (!comparer.Equals(a1[i], a2[i])) return false;
}
return true;
}
如果您可以使用 Linq (.NET Framework >= 3.5),请使用 SequenceEqual
【讨论】:
Array类中没有静态的Equals方法,所以你使用的其实是Object.Equals,它判断两个对象引用是否指向同一个对象。
如果要检查数组是否包含相同顺序的相同项,可以使用SequenceEquals扩展方法:
childe1.SequenceEqual(grandFatherNode)
要将SequenceEquals 与多维数组一起使用,您可以使用扩展来枚举它们。这是枚举二维数组的扩展:
public static IEnumerable<T> Flatten<T>(this T[,] items) {
for (int i = 0; i < items.GetLength(0); i++)
for (int j = 0; j < items.GetLength(1); j++)
yield return items[i, j];
}
用法:
childe1.Flatten().SequenceEqual(grandFatherNode.Flatten())
如果您的数组的维度多于两个,则您需要一个支持该维度的扩展。如果维数不同,则需要更复杂的代码来循环可变维数。
在比较数组的内容之前,您当然会首先确保数组的维数和维数的大小匹配。
事实证明,正如 RobertS 所指出的,您可以使用 OfType<T> 方法来展平数组。当然,只有在所有项目实际上都可以转换为相同类型的情况下才有效,但是如果您无论如何都可以比较它们,通常就是这种情况。示例:
childe1.OfType<Person>().SequenceEqual(grandFatherNode.OfType<Person>())
【讨论】:
Flatten 方法不会创建任何新数组,它只是将数组作为一维枚举访问的一种方式。
OfType<T> 来展平多维数组。无需创建新的扩展方法。
Array.Equals 比较的是参考文献,而不是它们的内容:
目前,当您使用 = 运算符比较两个数组时,我们实际上是在使用 System.Object 的 = 运算符,它只比较实例。 (即,这使用引用相等,因此只有当两个数组都指向完全相同的实例时才会为真)
如果你想比较数组的内容,你需要遍历数组并比较元素。
同一篇博文中提供了如何执行此操作的示例。基本实现是:
public static bool ArrayEquals<T>(T[] a, T[] b)
{
if (a.Length != b.Length)
{
return false;
}
for (int i = 0; i < a.Length; i++)
{
if (!a[i].Equals(b[i]))
{
return false;
}
}
return true;
}
虽然这会有性能问题。添加约束:
public static bool ArrayEquals<T>(T[] a, T[] b) where T: IEquatable<T>
会改进,但意味着代码仅适用于实现 IEquatable 的类型。
使用 EqualityComparer.Default 的 Equal 方法而不是对类型本身调用 Equals 也将提高性能,而无需类型实现 IEquatable。在这种情况下,方法的主体变为:
EqualityComparer<T> comparer = EqualityComparer<T>.Default;
for (int i = 0; i < a.Length; i++)
{
if (!comparer.Equals(a[i], b[i]))
{
return false;
}
}
【讨论】:
Equals 方法进行引用比较 - 如果数组是不同的对象,这确实会返回 false。
要检查数组是否包含相同的值(并且以相同的顺序),您需要遍历它们并测试每个数组的相等性。
【讨论】:
Array.Equals() 似乎只测试同一个实例。
似乎没有比较值的方法,但它很容易编写。
只比较长度,如果不相等,返回false。否则,遍历数组中的每个值并确定它们是否匹配。
【讨论】: