如何比较两个列表中的值?

14
我有两个列表。
List 01 => { A, B, C, D, E }
List 02 => { F, F, F, F, E }
我需要检查 List 02 中的一个元素是否存在于 List 01 中,所以应该返回 false
List 01 => { A, B, C, D, E }
List 02 => { F, F, F, F, F } // no element matches

这里应该是true

List 01 => { A, B, C, D, E }
List 02 => { F, F, F, F, B } // last element matches

我该如何检查这个?

我也关注性能问题。


https://dev59.com/VHVD5IYBdhLWcg3wO5ED - 0xAX
4个回答

13
list1.Intersect(list2).Any()

这将是最高效的,因为它使用了HashSets。


9

有几种不同的方法来做到这一点:

交集

如果交集的结果中有一个或多个元素,则表示至少有一个相等的元素。

var result = list01.Intersect(list02);
bool hasElement = result.Any();

我建议使用这种方法。

如果您需要比较复杂类型,可以将IEqualityComparer<T>作为第二个参数传递。

Except

如果except的结果总共有不同数量的元素,则表示至少存在一个相等的元素。

var result = list01.Except(list02);
bool hasElement = result.Count() != list01.Count;

如果需要比较复杂类型,则可以将 IEqualityComparer<T> 作为第二个参数传递。

任意类型

如果列表01中的任何元素等于列表02中的任何元素,则表示至少存在一个相等的元素。

bool hasElement = list01.Any(e => list02.Any(o => o == e));

AnyIndexOf

如果在list02中找到了list01中的任何一个元素,那么就意味着至少存在一个相等的元素。

bool hasElement = list01.Any(e => list02.IndexOf(e) != -1);
IndexOf的缺点是无法传递IEqualityComparer<T>,相反它总会使用默认值EqualityComparer<T>.Default

性能

在一个大列表中,只有当第一个值包含在第二个列表中时,list01.Any(e => list02.Any(o => o == e))才能具有良好的性能。否则,性能将非常糟糕,因为迭代是连续的。

在性能测试中,我得到了以下结果:

每个列表都有5个元素,测试了10000000次。

Intersect     : 00:00:02.9260135
Except        : 00:00:03.4404527
AnyAny        : 00:00:06.5709693
AnyIndexOf    : 00:00:01.9882278

每个列表中有10万个元素,测试500次。list02的最后一个元素等于list01中的第三个元素:

Intersect     : 00:00:02.4397784
Except        : 00:00:04.2595364
AnyAny        : 00:00:02.9761128
AnyIndexOf    : 00:00:00.0919344

测试了500次,每个列表都有100000个元素。list02的最后一个元素等于list01中的最后一个元素。

Intersect     : 00:00:02.4927969
Except        : 00:00:04.2668677
AnyAny        : more than a minute and I dropped the test
AnyIndexOf    : more than a minute and I dropped the test

5

Enumerable.Except & Enumerable.Intersect.


1
感谢您对另一个答案的评论。我已经使用两个大小为“1000”的列表进行了测试。使用“Intersect”与“Any”和“Contains”相比,结果是大约1300个滴答声与大约32000个滴答声(使用秒表测试)。 - BrunoLM

3

尝试

list1.Any(e => list2.Contains(e));

e.g.

var list1 = new List<string> { "A", "B", "C", "D" };
var list2 = new List<string> { "F", "F", "F" };

list1.Any(e => list2.Contains(e)); // returns false

var list3 = new List<string> { "F", "F", "D" };

list1.Any(e => list3.Contains(e)); // returns true

更新:正如leppie所指出的,如果列表很大,使用Intersect会更加高效。


4
虽然这个解决方案是正确的,但它的时间复杂度为 O(n^2),而其他方法(由我提出)的时间复杂度为 O(n)。 - leppie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接