如何解决C#LINQ First比ToArray[0]快吗?
| 我正在测试。 看起来像: 方法1)List<int> = new List<int>{1,2,4,.....} //assume 1000k
var result ErrorCodes.Where(x => ReturnedErrorCodes.Contains(x)).First();
方法2)
List<int> = new List<int>{1,.....} //assume 1000k
var result = ErrorCodes.Where(x => ReturnedErrorCodes.Contains(x)).ToArray()[0];
为什么方法2与方法1相比这么慢?
解决方法
Erm ...,因为您正在创建一个额外的数组(而不仅仅是使用迭代器)。第一种方法在第一个匹配项之后停止(
Where
是非缓冲流API)。第二个将所有匹配项加载到一个数组中(大概具有几个调整大小),然后获取第一个项。
作为旁注;您可以创建无限序列;第一种方法仍然有效,第二种方法将永远运行(或爆炸)。
也可能是:
var result ErrorCodes.First(x => ReturnedErrorCodes.Contains(x));
(这不会使其更快,但可能更易于阅读)
,您有一个装有一千个硬币的罐子,其中许多是一角钱。你要一角钱。这是解决问题的两种方法:
一次从罐子中取出硬币,直到得到一角钱为止。现在你有一角钱。
一次将硬币从罐子中拉出,将一角硬币放入另一个罐子中。如果那个广口瓶太小,则一次将它们移到一个较大的广口瓶中。继续这样做,直到将所有硬币都放入最终罐中。那个罐子可能太大了。制造一个足够大的罐子,足以容纳那么多硬币,然后一次将一个硬币移动到新罐子中。现在开始从罐子里取出一角钱。取出第一个。现在你有一角钱。
现在是否清楚为什么方法1比方法2快很多?
,由于推迟执行。
代码“ 4”不返回整数集合,而是返回一个能够返回整数流的表达式。在您开始从中读取整数之前,它不会做任何实际的工作。
ToArray
方法将消耗整个流,并将所有整数放入数组中。这意味着必须将整个列表中的每个项目与错误代码进行比较。
另一方面,“ 6”方法将仅从流中获取第一项,然后停止从流中读取。这将使其速度更快,因为一旦找到匹配项,它将停止将列表中的项目与错误代码进行比较。
,因为“ 7”将整个序列复制到一个数组中。
方法2必须遍历整个序列以构建数组,然后返回第一个元素。
方法1仅遍历足够多的序列以找到第一个匹配元素。
,ToArray()
遍历给出的整个序列,并根据序列创建和排列。
如果您不叫ToArray()
,则First()
让Where()
只返回匹配的第一个项目并立即返回。
,First()是O(1)的复杂度
ToArray()[0]是复杂度O(n)+1
,var @e = array.GetEnumerator();
// First
@e.MoveNext();
return @e.Current;
// ToArray (with yield [0] should as fast as First...)
while (@e.MoveNext() {
yield return @e.Current;
}
,因为在第二个示例中,实际上是将IEnumerable<T>
转换为数组,而在第一个示例中,没有进行转换。
,在方法2中,必须首先将整个数组转换为数组。另外,当ѭ10更易读时,混合数组访问似乎很尴尬。
,这是有道理的,ToArray可能涉及一个副本,这总是会变得更昂贵,因为Linq无法保证您将如何使用数组,而First()只能返回单个元素一开始。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。