什么提供了C#中最快的成员资格查找?

时间:2017-07-02 16:17:50

标签: c# performance linq

为什么我们必须在lambda表达式中的任何本机容器上使用Contains()来避免成员资格查找?

1 个答案:

答案 0 :(得分:2)

让我们考虑以下几点:

var source = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var matches = new[] { 12, 2, 19, 8, 40, 12, 123, 121, 1212, 122334, 2, 102, 10, 29 };
foreach (var item in source.Where(i => matches.Contains(i)))
{
    Console.WriteLine(item);
}

现在,让我们考虑一下matches i中需要比较的项目数,然后再知道是否要写出来:

1: 14
2: 2
3: 14
5: 14
6: 14
7: 14
8: 4
9: 14
10: 13

虽然我们有时会很快得到答案,但我们通常不会特别提到答案是我们不应该这样做,所以我们进行了103次比较来处理10个项目。我们还浪费时间比较我们已经检查过的值(2matches两次的事实)。

我们正在执行O(m)次操作n次,因此算法为O(nm)

我们可以做得更好:

var source = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var matches = new HashSet<int> { 12, 2, 19, 8, 40, 12, 123, 121, 1212, 122334, 2, 102, 10, 29 };
foreach (var item in source.Where(i => matches.Contains(i)))
{
    Console.WriteLine(item);
}

由于哈希集上的ContainsO(1),因此算法总体上为O(n),这与它的效果差不多。

要注意的一些重要事项是:

  1. 如果以上是在数据库上完成的,那么无论类型matches是什么,它都会变成SQL生成的CONTAINS子句的WHERE部分,所以它无关紧要(CONTAINS仍然比=慢到一定数量的链接=,但游戏中的因素不同。

  2. 使用相对较小的匹配项,O(n)成本Contains比创建和搜索哈希集的常量成本更便宜。 (以上示例可能需要大约相同的时间才能运行)。

  3. 所以这不是永远不会做的事情,而是你应该了解成本以及它们如何受源数据及其运行方式的影响,以及如何在成本特别高的情况下提高性能。< / p>

    我们使用lambdas并不是特别重要,除了lambdas让我们快速编写一些代码让我们快速编写一些隐藏低效的代码,而如果我们必须写两个单独的foreach循环算法O(nm)会更明显。