比较两个list时出现奇怪的结果
本文关键字:结果 list 两个 比较 | 更新日期: 2023-09-27 18:08:28
我想比较两个列表。我想检查List2是否有List1中的任何项。我得到了意想不到的结果。请参阅下面我的代码。
测试代码类
class Program
{
static void Main(string[] args)
{
bool loop = true;
int textcount = 1;
while (loop)
{
var collection1 = GetCollection();
var collection2 = GetCollection();
Console.WriteLine("Test No " + textcount.ToString());
Console.WriteLine("Collection 1 =" + String.Join(", ", collection1.ToArray()));
Console.WriteLine("Collection 2 =" + String.Join(", ", collection2.ToArray()));
System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
watch.Start();
var hasitem = collection1.Any(item => collection2.Contains(item));
watch.Stop();
Console.WriteLine(hasitem.ToString() + " Found in " + watch.ElapsedTicks.ToString());
watch.Reset();
watch.Start();
var hasAtLeastOne = collection1.Intersect(collection2).Any();
watch.Stop();
Console.WriteLine(hasAtLeastOne.ToString() + " With Intersect Found in " + watch.ElapsedTicks.ToString());
textcount++;
Console.ReadKey();
}
}
static Random ran = new Random();
private static IEnumerable<int> GetCollection()
{
for (int i = 0; i < 5; i++)
{
yield return ran.Next(i, 20);
}
}
}
,结果非常烦人。查看最后4个结果
Test No 1
Collection 1 =10, 8, 18, 6, 11
Collection 2 =3, 12, 18, 13, 6
True Found in 3075
True With Intersect Found in 15297
Test No 2
Collection 1 =18, 13, 7, 18, 5
Collection 2 =12, 18, 8, 3, 5
True Found in 22
True With Intersect Found in 100
Test No 3
Collection 1 =1, 6, 15, 7, 9
Collection 2 =16, 15, 14, 14, 12
True Found in 21
True With Intersect Found in 23
Test No 4
Collection 1 =3, 16, 7, 4, 19
Collection 2 =6, 3, 15, 15, 9
True Found in 21
True With Intersect Found in 56
Test No 5
Collection 1 =18, 18, 9, 17, 10
Collection 2 =17, 12, 4, 3, 11
True Found in 25
True With Intersect Found in 20
Test No 6
Collection 1 =9, 9, 2, 17, 19
Collection 2 =17, 2, 18, 3, 15
False Found in 109
False With Intersect Found in 41
Test No 7
Collection 1 =3, 15, 3, 5, 5
Collection 2 =2, 2, 11, 7, 6
True Found in 22
False With Intersect Found in 15
Test No 8
Collection 1 =7, 14, 17, 14, 18
Collection 2 =18, 4, 7, 18, 16
False Found in 28
True With Intersect Found in 19
Test No 9
Collection 1 =3, 9, 6, 18, 9
Collection 2 =10, 3, 17, 17, 18
True Found in 28
True With Intersect Found in 22
Test No 10
Collection 1 =15, 18, 2, 9, 8
Collection 2 =10, 15, 3, 10, 19
False Found in 135
True With Intersect Found in 128
Test No 11
Collection 1 =6, 2, 17, 18, 18
Collection 2 =14, 16, 14, 6, 4
False Found in 20
False With Intersect Found in 17
问题是,您所说的"集合"实际上是一个不稳定的项目序列,每次枚举时都会发生变化。原因在于您实现GetCollection
的方式。使用yield return
基本上返回如何创建序列的蓝图。它不返回序列本身。
因此,每次"蓝图"被枚举时,它就被用来创建一个新的序列。您可以通过简单地输出两次"集合"来验证这一点。您将看到每次的值都是不同的。
这就是为什么你的测试产生完全任意的结果:将每个集合枚举三次:
- 第一个枚举发生在输出到控制台 时。
- 第二次枚举发生在
Any
和Contains
的测试中。因为这将启动一个新的枚举,因此将生成新的随机数。 - 第三次枚举发生在
Intersect
测试上。这将创建另一组随机数。
要解决这个问题,可以在GetCollection
的结果上调用ToArray()
来创建一个稳定的序列。
这就是你的问题:
private static IEnumerable<int> GetCollection()
{
for (int i = 0; i < 5; i++)
{
yield return ran.Next(i, 20);
}
}
改成:
private static List<int> GetCollection()
{
return new List<int>
{
ran.Next(0, 20),
ran.Next(1, 20),
ran.Next(2, 20),
ran.Next(3, 20),
ran.Next(4, 20)
};
}
你的问题就会消失。
一个很长的解释是,当你创建一个IEnumerable函数时,你可以期望它在各种LINQ调用时重复调用迭代器(毕竟,这就是IEnumerable所做的,对吧?)由于每次迭代器调用都执行yield return <some random number>
操作,因此可能会得到不稳定的结果。最好保存对.ToArray()
结果的引用,或者只返回一个稳定的列表。