将 Linq Except 与两个 int 数组列表一起使用
Using Linq Except with two lists of int arrays
是否可以将 except 与两个 int 数组列表一起使用,如下所示:
List<int[]> a = new List<int[]>(){ new int[]{3,4,5}, new int[]{7,8,9}, new int[]{10,11,12} };
List<int[]> b = new List<int[]>(){ new int[]{6,7,9}, new int[]{3,4,5}, new int[]{10,41,12} };
var c = a.Except(b);
并期望 {3,4,5} 不存在于可枚举的 c 中?当然我试过了,但这个不起作用。有没有像 Except 一样高效的解决方案?或者更好、更快?
这是因为 int 数组的默认 EqualityComparer returns false 对于具有相同值的数组:
int[] a1 = { 1, 2, 3 };
int[] a2 = { 1, 2, 3 };
var ec = EqualityComparer<int[]>.Default;
Console.WriteLine(ec.Equals(a1, a2));//result is false
您可以通过实现自己的 EqualityComparer 并将其实例传递给 Except 方法 (see documentation) 来修复它。
您还可以阅读 C# 中的数组比较 here。
在 .NET 中,只有当数组是完全相同的数组对象时,数组才与另一个数组相等。所以两个具有相同内容的不同数组不被认为是相等的:
int[] x = new int[] { 1, 2 };
int[] y = new int[] { 1, 2 };
Console.WriteLine(x == y); // false
为了根据内容检查是否相等,可以使用Enumerable.SequenceEqual
:
Console.WriteLine(x.SequenceEqual(y)); // true
当然,当你尝试使用 Enumerable.Except
时,这并不能直接帮助你,因为默认情况下,它将使用默认的相等比较器,它只检查是否相等(并且因为每个数组都与其他数组不相等除了它自己……)。
所以解决方案是use the other overload, and provide a custom IEqualityComparer
,它根据内容比较数组。
public class IntArrayEqualityComparer : IEqualityComparer<int[]>
{
public bool Equals(int[] a, int[] b)
{
return a.SequenceEqual(b);
}
public int GetHashCode(int[] a)
{
return a.Sum();
}
}
不幸的是,仅仅委派给 SequenceEqual
是不够的。我们还必须提供 GetHashCode
实现才能使其正常工作。作为一个简单的解决方案,我们可以在这里使用数组中数字的总和。通常,我们希望提供一个强大的散列函数,它可以告诉我们很多关于内容的信息,但由于我们只将这个散列函数用于 Except
调用,我们可以在这里使用一些简单的东西。 (一般来说,我们也希望避免从可变对象创建哈希值)
并且在使用相等比较器时,我们正确地过滤掉了重复的数组:
var c = a.Except(b, new IntArrayEqualityComparer());
是否可以将 except 与两个 int 数组列表一起使用,如下所示:
List<int[]> a = new List<int[]>(){ new int[]{3,4,5}, new int[]{7,8,9}, new int[]{10,11,12} };
List<int[]> b = new List<int[]>(){ new int[]{6,7,9}, new int[]{3,4,5}, new int[]{10,41,12} };
var c = a.Except(b);
并期望 {3,4,5} 不存在于可枚举的 c 中?当然我试过了,但这个不起作用。有没有像 Except 一样高效的解决方案?或者更好、更快?
这是因为 int 数组的默认 EqualityComparer returns false 对于具有相同值的数组:
int[] a1 = { 1, 2, 3 };
int[] a2 = { 1, 2, 3 };
var ec = EqualityComparer<int[]>.Default;
Console.WriteLine(ec.Equals(a1, a2));//result is false
您可以通过实现自己的 EqualityComparer 并将其实例传递给 Except 方法 (see documentation) 来修复它。
您还可以阅读 C# 中的数组比较 here。
在 .NET 中,只有当数组是完全相同的数组对象时,数组才与另一个数组相等。所以两个具有相同内容的不同数组不被认为是相等的:
int[] x = new int[] { 1, 2 };
int[] y = new int[] { 1, 2 };
Console.WriteLine(x == y); // false
为了根据内容检查是否相等,可以使用Enumerable.SequenceEqual
:
Console.WriteLine(x.SequenceEqual(y)); // true
当然,当你尝试使用 Enumerable.Except
时,这并不能直接帮助你,因为默认情况下,它将使用默认的相等比较器,它只检查是否相等(并且因为每个数组都与其他数组不相等除了它自己……)。
所以解决方案是use the other overload, and provide a custom IEqualityComparer
,它根据内容比较数组。
public class IntArrayEqualityComparer : IEqualityComparer<int[]>
{
public bool Equals(int[] a, int[] b)
{
return a.SequenceEqual(b);
}
public int GetHashCode(int[] a)
{
return a.Sum();
}
}
不幸的是,仅仅委派给 SequenceEqual
是不够的。我们还必须提供 GetHashCode
实现才能使其正常工作。作为一个简单的解决方案,我们可以在这里使用数组中数字的总和。通常,我们希望提供一个强大的散列函数,它可以告诉我们很多关于内容的信息,但由于我们只将这个散列函数用于 Except
调用,我们可以在这里使用一些简单的东西。 (一般来说,我们也希望避免从可变对象创建哈希值)
并且在使用相等比较器时,我们正确地过滤掉了重复的数组:
var c = a.Except(b, new IntArrayEqualityComparer());