2015-05-27 21 views
1

List<T>()System.Collections.Generic缺省容量是0提供大小参数来列出<T>()

说我有一个功能

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是'动态'?

+0

试试看看。为预期内容提供足够大的尺寸将防止发生在引擎盖下的重新分配。 –

+1

但是,如果你只是在一个列表上进行转换,为什么不使用LINQ的Select()? –

回答

5

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

e.Count() 

可以列举e只是指望它......如果e兑数据库查询时,它会在被执行两次,一次e.Count()和一次为foreach ...慢!

如果eList<>OtherType[]或其他类型的实现ICollection<>那么Count()使用Count属性,因此它不枚举IEnumerable<>

注意,对于你可以这个简单的例子:

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

现在...作为@Jonathan注意到,您在返回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); 

与往常一样,请记住,你不应列举的IEnumerable<>不止一次,除非你是真的确保

  1. 这实在是一种变相的List<>或其他集合,从而使数据已经存在,并且没有问题枚举它多次

  • 你知道每次IEnumerable<>枚举将从头开始重建,但成本可以忽略不计。
  • +0

    ToList为什么? –

    +0

    “选择”是1到1列表的路线。 – Franck

    +0

    @JonathonReinhart因为他正在构建一个'List <>'可以在缓存IEnumerable <>'时有一些时间差别:-)是的......如果你想要的话,你可以去掉ToList <>() – xanatos

    3

    不要这样做。这样,你可以列举两次序列e:一次在foreach之内,一次通过Count()

    将容量赋予List<T>构造函数的想法是防止不必要的数组分配。该列表动态增长,这意味着它将分配一个新的数组,这个数组的长度是必要时的两倍。如果它知道所需容量,List<T>可以从一开始就分配正确大小的数组。

    有关的一般建议是否会影响运行时间度量值,请不要假设为。你可以在这里节省数组的分配,但是你可能会比较慢,因为你不止一次遍历序列。

    +0

    取决于IEnumerable的类型,但它是一个好点 – Jehof

    +0

    *可能*。 .Count()可以专门用于像数组这样的事物,并且可以在O(1)中运行,因为大小是已知的。 –

    +0

    是的,你是对的。但由于'DoStuff'接受任何序列,所以不应该迭代多次。不过,您可以尝试进行演员制作,并根据此决定作出决定。 –