【问题标题】:Fastest way to convert List<int> to List<int?>将 List<int> 转换为 List<int?> 的最快方法
【发布时间】:2013-02-17 12:55:40
【问题描述】:

获取原语列表并将其转换为可为空的原语列表的最快方法是什么?例如:List&lt;int&gt; 到 List&lt;int?&gt;。

简单的解决方案是创建一个新列表并使用foreach 循环添加每个项目,这需要太多时间。

【问题讨论】:

  • 你对太多时间的定义是什么?唯一的方法是循环(使用foreach 或LINQ)
  • 不是很聪明,但你不能稍微重构你的代码,这样你就不必转换了吗?

标签: c# performance linq


【解决方案1】:

没有比创建新列表更快的方法了:

var newList = list.Select( i => (int?)i ).ToList();

但是使用 LINQ 比使用裸循环要慢。

最快的方法是使用具有预分配容量的List&lt;int?&gt;:

List<int?> newList = new List<int?>(list.Count); // Allocate enough memory for all items
foreach (var i in list)
    newList.Add(i);

如果您正在寻找列表项的就地类型更改,这是不可能的。

【讨论】:

  • 不使用 LINQ 会更快。
  • @JeffMercado 实际上,我同意 :-) 我没有测量性能差异,但我想它可以忽略不计。
  • @Fuex 有趣。我的测试还表明,裸循环比 LINQ(有 1,000,000 个)项目快 30%-40%。
  • 你真的怎么知道迭代项目会胜过Cast方法之类的东西?! :)) 我敢打赌你以前没有测量过!
  • @ArmanEbrahimpour 我测量了?这个答案是 7 年前的。我知道 LINQ 运算符会增加一些开销,但我认为它可以忽略不计。现在我了解了所有开销以及可能消除开销的编译器和运行时优化!请记住,您应该始终在优化之前进行测量!
【解决方案2】:

您可以坚持使用Cast LINQ 运算符,而不是Select:

List<int> first = new List<int>() {1, 2, 3};
List<int?> second = first.Cast<int?>().ToList();

【讨论】:

  • 比Select慢
  • 你能证明吗?
  • 查看同一问题的其他答案
【解决方案3】:

如果你想知道什么是更快的解决方案,你应该通过使用三种不同的方式来做一点benchmark:

List<int> list = Enumerable.Range( 0, 10000 ).ToList( );
Stopwatch sw = Stopwatch.StartNew( );

for ( int i = 0; i < 100000; i++ ) {
   List<int?> newList = new List<int?>( );
   foreach( int integer in list )
      newList.Add( ( int? ) integer );
}

sw.Stop( );
TimeSpan timespan = sw.Elapsed;
Console.WriteLine( String.Format( "Foreach: {0:00}:{1:00}:{2:00}", timespan.Minutes, timespan.Seconds, timespan.Milliseconds / 10 ) );
sw.Restart( );

for ( int i = 0; i < 100000; i++ ){
   List<int?> newList = list.Select( x => ( int? ) x ).ToList( );
}

sw.Stop( );
timespan = sw.Elapsed;
Console.WriteLine( String.Format( "LINQ-Select: {0:00}:{1:00}:{2:00}", timespan.Minutes, timespan.Seconds, timespan.Milliseconds / 10 ) );
sw.Restart( );

for ( int i = 0; i < 100000; i++ ){
   List<int?> newList = list.Cast<int?>( ).ToList( );
}

sw.Stop();
timespan = sw.Elapsed;
Console.WriteLine( String.Format( "LINQ-Cast: {0:00}:{1:00}:{2:00}", timespan.Minutes, timespan.Seconds, timespan.Milliseconds / 10 ) );

结果:

正如我们所料,最好的方法是第一个解决方案 (foreach),这意味着循环遍历元素、强制转换并将它们添加到新列表中。

【讨论】:

  • 您是否尝试过不使用 foreach 并使用简单的“for(i = 0; i stackoverflow.com/questions/365615/…
  • 有趣的事实,所以我提供的 SO-Answer 有点过时 ;)
  • 不要忘记在foreach案例中设置列表的Capacity,让它更快更精简。
【解决方案4】:

这不是一个新问题,但我目前使用此代码;我分享它,希望它可以帮助其他有同样问题的人: 带有预分配 + Linq 的列表:

var branchIds = new List<int?>(branches.Count);
branchIds.AddRange(branches.Select(int.Parse).Select(brId => (int?)brId));

【讨论】:

  • 您没有显示branches 是什么,但由于您使用int.Parse 转换它,它必须是一些string 集合,而问题是如何创建List&lt;int?&gt;来自List&lt;int&gt;。
猜你喜欢
  • 1970-01-01
  • 2012-11-24
  • 1970-01-01
  • 2013-01-01
  • 1970-01-01
  • 2018-04-28
  • 2016-12-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多