在C#中将IEnumerable <t>转换为List <t>的最快方法

时间:2019-01-21 21:33:08

标签: c# list collections iterator ienumerable

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

我的第一个想法是:

List<int> list = new List<int>();
foreach(int number in iterator)
    list.Add(number);

有更快的方法吗?

1 个答案:

答案 0 :(得分:1)

在谈到List<T>时,实际上您有2种方法,我将在下面讨论。为了清楚起见,假设List<T>的分配需要固定的时间(C),向List<T>添加元素也需要固定的时间。


创建空的List<T>并填充

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

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


根据其他List<T>

创建IEnumerable<T>
List<int> list = new List<int>(iterator);

但是,关于迭代器的类型有一个小的区别:

  1. 如果迭代器为ICollection<T>

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

  2. 如果迭代器为IEnumerable<T>,则与创建空并逐项添加项相同。

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

但是...

List<T>的增长和容量有一个警告,可能会影响性能。默认的List<T>容量为4,如果您向List<T>添加了4个以上的元素,则将分配新的基础数组,大小是当前大小的两倍,并且将复制这些元素...此过程当我们达到List<T>的容量时,将再次重复。您可以想象有多少不必要的复制。为了防止这种情况,最好的选择是预先使用容量初始化List<T>或使用List<T>(ICollection<T>) 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);