为List <t>()提供大小参数

时间:2015-05-27 11:27:56

标签: c# performance list

List<T>()System.Collections.Generic的默认容量为0。

说我有一个功能

private IEnumerable<SomeType> DoStuff(IEnumerable<OtherType> e)
{
    var list = new List<SomeType>();
    foreach (var elem in e)
    {
        list.Add(new SomeType
        {
            SomeProperty = elem.OtherProperty
        });
    }
    return list;
}

我在运行循环之前设置了list的大小,如下所示:

private IEnumerable<SomeType> DoStuff(IEnumerable<OtherType> e)
{
    var list = new List<SomeType>(e.Count());
    foreach (var elem in e)
    {
        list.Add(new SomeType
        {
            SomeProperty = elem.OtherProperty
        });
    }
    return list;
}

它是否会影响运行时间,或者没有理由这样做,因为e的大小是动态的&#39;?

2 个答案:

答案 0 :(得分:5)

这取决于IEnumerable<OtherType> e ...

的类型
e.Count()

可以枚举e只计算它......如果e是对数据库的查询,它将被执行两次,一次为e.Count(),一次为{ {1}} ......慢!

如果foreacheList<>或实施OtherType[]的其他类型,则ICollection<>使用Count()属性,它没有枚举Count

请注意,对于这个简单的案例,您可以:

IEnumerable<>

现在......正如@Jonathan注意到的那样,你正在返回一个return e.Select(x => new SomeType { SomeProperty = x.OtherProperty }) .ToList(); ,所以你可以:

IEnumerable<>

并且幸福快乐......或者你可以

return e.Select(x => new SomeType { SomeProperty = x.OtherProperty });

(这几乎等同于执行private IEnumerable<SomeType> DoStuff(IEnumerable<OtherType> e) { foreach (var elem in e) { yield return new SomeType { SomeProperty = elem.OtherProperty }; } } ,但是如果你有一个复杂的表达式来转换元素,那么使用Select会变得很麻烦)

或者,如果你真的想创建一个Select并在可能的情况下加以预测:

List<>

与往常一样,请记住,不应多次枚举ICollection<T> c = e as ICollection<T>; int count = c != null ? c.Count : 0; var list = new List<SomeType>(count); ,除非您确实确定

  1. 它实际上是一个IEnumerable<>或其他伪装集合,因此数据已经存在,并且多次枚举它没有问题
    1. 您知道每次枚举List<>时都会从头开始重建,但费用可以忽略不计。

答案 1 :(得分:3)

不要这样做。这样,您就可以对序列e进行两次枚举:一次在foreach内,一次到{{1} }。

Count()构造函数提供容量背后的想法是防止不必要的数组分配。该列表动态增长,这意味着它会在必要时分配一个新数组,该数组的长度是其两倍。如果它预先知道所需的容量,List<T>可以从一开始就分配一个正确大小的数组。

关于的一般建议是否会影响运行时间衡量,不要假设。你可以在这里保存数组分配,但是你可能会慢一点,因为你不止一次地迭代序列。