比较两个序列是否相等
本文关键字:是否 两个 比较 | 更新日期: 2023-09-27 18:25:19
在因其标题将其标记为重复之前,请考虑以下简短程序:
static void Main()
{
var expected = new List<long[]> { new[] { Convert.ToInt64(1), Convert.ToInt64(999999) } };
var actual = DoSomething();
if (!actual.SequenceEqual(expected)) throw new Exception();
}
static IEnumerable<long[]> DoSomething()
{
yield return new[] { Convert.ToInt64(1), Convert.ToInt64(999999) };
}
我有一个返回 long 类型的数组序列的方法。为了测试它,我编写了一些类似于 Main
中的测试代码。
但是我得到了例外,但我不知道为什么。预期的序列不应该与实际返回的序列相当,还是我错过了什么?
对我来说,方法和epxected
似乎都只包含一个包含 long 类型数组的单个元素,不是吗?
编辑:那么我如何实现不获取异常含义来比较枚举中的元素以返回相等性?
实际问题是您正在比较两个long[]
,并且Enumerable.SequenceEquals
将使用一个ObjectEqualityComparer<Int64[]>
(您可以通过检查EqualityComparer<long[]>.Default
看到这是Enumerable.SequenceEquals
内部使用的内容(,它将比较这两个数组的引用,而不是存储在数组中的实际值,这显然是不一样的。
要解决此问题,您可以编写一个自定义EqualityComparer<long[]>
:
static void Main()
{
var expected = new List<long[]>
{ new[] { Convert.ToInt64(1), Convert.ToInt64(999999) } };
var actual = DoSomething();
if (!actual.SequenceEqual(expected, new LongArrayComparer()))
throw new Exception();
}
public class LongArrayComparer : EqualityComparer<long[]>
{
public override bool Equals(long[] first, long[] second)
{
return first.SequenceEqual(second);
}
// GetHashCode implementation in the courtesy of @JonSkeet
// from http://stackoverflow.com/questions/7244699/gethashcode-on-byte-array
public override int GetHashCode(long[] arr)
{
unchecked
{
if (array == null)
{
return 0;
}
int hash = 17;
foreach (long element in arr)
{
hash = hash * 31 + element.GetHashCode();
}
return hash;
}
}
}
不,你的序列不相等!
让我们删除序列位,只取每个项目的第一个元素中的内容
var firstExpected = new[] { Convert.ToInt64(1), Convert.ToInt64(999999) };
var firstActual = new[] { Convert.ToInt64(1), Convert.ToInt64(999999) };
Console.WriteLine(firstExpected == firstActual); // writes "false"
上面的代码比较两个单独的数组是否相等。相等不检查数组的内容,它检查引用的相等性。
使用SequenceEquals
的代码本质上是在做同样的事情。它检查可枚举项中每个元素的每个情况下的引用。
SequenceEquals
测试序列中的元素是否相同。枚举中的元素是 long[]
类型,所以我们实际上将两个不同的数组(但包含相同的元素(相互比较,这是通过比较它们的引用而不是它们的实际值来痴迷地完成的。
所以我们在这里实际检查的是这个expected[0] == actual[0]
而不是expected[0].SequqnceEquals(actual[0])
这是 obbiosuly 返回false
因为两个数组共享不同的引用。
如果我们使用 SelectMany
扁平层次结构,我们会得到我们想要的:
if (!actual.SelectMany(x => x).SequenceEqual(expected.SelectMany(x => x))) throw new Exception();
编辑:
基于这种方法,我找到了另一种优雅的方法来检查expected
中的所有元素是否也包含在actual
中:
if (!expected.All(x => actual.Any(y => y.SequenceEqual(x)))) throw new Exception();
这将搜索expected
内是否有与当前列表顺序相同的列表actual
子列表。这似乎更聪明,因为我们不需要任何自定义EqualityComparer
,也没有奇怪的哈希码实现。