【问题标题】:Fastest way to convert IEnumerable<T> to List<T> in C#在 C# 中将 IEnumerable<T> 转换为 List<T> 的最快方法
【发布时间】:2019-06-15 07:41:03
【问题描述】:

在 C# 中,就编写代码所需的时间而言,使用IEnumerable 创建和填充列表的最快方法是什么?执行所需的时间呢?

我的第一个想法是这样的:

List<int> list = new List<int>();

foreach(int number in iterator)
    list.Add(number);

有没有更快的方法?

【问题讨论】:

  • enumerable.ToList()?
  • 有可用的优化,具体取决于IEnumerable 的类型。如果您能提供minimal reproducible example,那就太好了。
  • '“执行速度最快”可能与“写入速度最快”、可读性、可维护性等相互竞争。后一个问题可以被认为比执行时间更重要。除非不是。
  • List&lt;int&gt; list = iterator.ToList(); 将调用new List&lt;int&gt;(iterator),它将分析所提供的集合类型,针对一些基本场景进行优化,然后在所有其他方法都失败时回退到您拥有的代码。为什么你需要找到比这更快的方法?下一个优化方法是,如果你不能让代码更快,运行它的次数更少,那么你真的需要构造那个列表吗?

标签: c# list collections iterator ienumerable


【解决方案1】:

谈到List&lt;T&gt;,基本上你有两种方法,我将在下面讨论。为了清楚起见,我们假设List&lt;T&gt; 的分配需要固定时间(C),向List&lt;T&gt; 添加元素也需要固定时间。


创建空的List&lt;T&gt; 并填充它

List<int> list = new List<int>(); // C
foreach(int i in iterator)
{
    list.Add(i); //n*C
}

如您所见,这种方法需要 n*C + C 时间,因此如果您忽略 C,则复杂度为 O(n)。


在另一个IEnumerable&lt;T&gt;的基础上创建List&lt;T&gt;

List<int> list = new List<int>(iterator);

但是,迭代器的类型有一点不同:

  1. 如果迭代器是ICollection&lt;T&gt;

    var array = new T[ICollection.Count] // C ICollection.CopyTo(array) // 来自 MSDN O(n)

  2. 如果迭代器是IEnumerable&lt;T&gt;,和创建空一样逐项添加

因此,如果您分析复杂性,就无法避免 O(n) 复杂性。

但是...

List&lt;T&gt; 的增长和容量有一个警告可能会影响性能。默认 List&lt;T&gt; 容量为 4,如果您向 List&lt;T&gt; 添加超过 4 个元素,则将分配两倍于当前大小的新底层数组,并将复制元素...此过程将再次重复我们达到了List&lt;T&gt; 的容量。你可以想象你可能有多少不必要的复制。为了防止这种情况,最好的选择是提前用容量初始化List&lt;T&gt;,或者使用List&lt;T&gt;(ICollection&lt;T&gt;) ctor。

// benchmark example
var enumerable = Enumerable.Repeat(1, 1000000);
var collection = enumerable.ToList();

Stopwatch st = Stopwatch.StartNew();
List<int> copy1 = new List<int>(enumerable);
Console.WriteLine(st.ElapsedMilliseconds);

st = Stopwatch.StartNew();
List<int> copy2 = new List<int>(collection);
Console.WriteLine(st.ElapsedMilliseconds);

【讨论】:

  • 哇,非常全面和有用的答案。非常感谢!
  • 当涉及到调整数组大小时:这个时间是真实的,但是调整大小的摊销时间被接受为 O(1) 因为最后一个需要调整大小的插入在大多数 N/2 移动(如您的示例中容量翻倍)。因此,整个序列的移动总数为:N/2 + N/4 + ... + 2 + 1 .
猜你喜欢
  • 2012-02-24
  • 2021-12-02
  • 2010-09-07
  • 2010-10-04
  • 1970-01-01
  • 2012-03-10
  • 2018-08-04
  • 1970-01-01
相关资源
最近更新 更多