我需要迭代和计数。啥是最快或首选:ToArray() 或 ToList()? [复制]

Posted

技术标签:

【中文标题】我需要迭代和计数。啥是最快或首选:ToArray() 或 ToList()? [复制]【英文标题】:I need to iterate and count. What is fastest or preferred: ToArray() or ToList()? [duplicate]我需要迭代和计数。什么是最快或首选:ToArray() 或 ToList()? [复制] 【发布时间】:2010-12-22 01:12:44 【问题描述】:

可能重复:Is it better to call ToList() or ToArray() in LINQ queries?

我有这样的代码:

void Foobar(string[] arr, Dictionary<string, string[]>)

   var t = arr.Intersect(dic.Keys).ToList(); // .or ToArray() ?
   foreach(var item in t)
   
      ..
   

   var j = t.Count; // also I need this

首选哪种方法?

我可以不带任何东西,但我需要知道大小,我不想打电话给Enumerable.Count&lt;T&gt;() - 似乎比Array&lt;T&gt;.SizeList&lt;T&gt;.Count 做更多的动作。我说的对吗?

【问题讨论】:

相关:Is it better to call ToList() or ToArray() in LINQ queries? 【参考方案1】:

实际上,在 Count(IEnumerable) 的当前 MS 实现中,有一个快捷方式可以查看 IEnumerable 是否为 ICollection 并在其上调用 Count。所以计算元素的性能应该是可比的。

ToList 和 ToArray 有点相同。如果 IEnumerable 是 ICollection,则改为调用 CopyTo 方法,这样会快一些。

因此,请选择使您的代码最易读的因素,并为您的用例进行基准测试以获得明确的答案。

更新: 我做了一个简单的基准测试。

从数组开始:var items = Enumerable.Range(1,1000).ToArray();

调用 ToList() : 25ms / 10000 调用 ToArray() : 23 ms / 10000

以 IEnumerable 开头:var items = Enumerable.Range(1,1000);

调用 ToList() : 168ms / 10000 调用 ToArray() : 171 ms / 10000

所以基本上你会得到相当的性能。

【讨论】:

【参考方案2】:

如果您真的关心性能,您应该遍历IEnumerable 并随时计算它。这避免了必须完全创建一个新集合,并且交集只需迭代一次:

void Foobar(string[] arr, Dictionary<string, string[]>)

   var t = arr.Intersect(dic.Keys);
   int count = 0;
   foreach(var item in t)
   
      count++;
      ..
   

   var j = count;

但就像其他人所说:这有微优化的味道。如果在这种情况下性能真的很重要,至少要进行性能分析以找出哪种方法对您来说确实是最快的。

【讨论】:

但是如果您非常关心性能,那么这意味着您必须为具有 X 个项目的 IEnumerable 更新计数器变量 X 次 - 与查找 Count 相比,这可能更有效大收藏。 @Yaakov:必须计算集合的大小。通过计算自己,您只需遍历集合一次。如果将集合转换为列表数组,则集合必须至少交互两次(一次用于转换,一次用于foreach 循环。 根据反射器,List、ArrayList 和 Array 各自在执行直接计数时引用的对象内保存一个长度或大小变量 - 因此在 Array 或 List 上运行 Count 不会引起另一个枚举。 @Yaakov:不,关键是从枚举创建数组或列表会导致创建迭代。然后,您必须遍历对创建的数组或列表进行的任何处理。相反,只需枚举收集计数和处理过程即可。 @jason 为了避免在我不需要一次全部创建列表/数组时重新枚举枚举并且我需要它们在同一个枚举的不同位置,你有什么建议?跨度> 【参考方案3】:

差异可能很小,值得使用更适合您需求的方法。微优化的味道。

在这种情况下,既然您所做的只是枚举集合并计算集合(这两者都可以使用 IEnumerable 完成),为什么不将其保留为 IEnumerable?

【讨论】:

我想这自然会引出另一个问题:由于大多数意图和目的的性能是相同的,我应该使用哪种类型作为我的“默认”集合类型?我个人更喜欢List&lt;T&gt;,因为它的长度不是只读的,但过去我很难说服其他人它比T[] 提供了更好的“默认”集合类型选择。 @romkyns:绝对是,这是一个通用的默认类。我更喜欢将数组作为固定长度的集合。我只在明确需要时才使用动态长度 为了避免在我不需要一次全部并且需要它们在同一个可枚举的不同位置时重新枚举用于创建列表/数组的枚举,您有什么建议?

以上是关于我需要迭代和计数。啥是最快或首选:ToArray() 或 ToList()? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

HashMap 或 TreeMap 或 LinkedHashMap 哪个迭代最快?

querySelectorAll vs NodeIterator vs TreeWalker - 最快的纯JS平面DOM迭代器[关闭]

哪个最快?计数子查询或分组依据

使用迭代器的最快(最 Pythonic)方式

迭代文件系统的最快方法

使用对象和键迭代 NSArray 的最快方法