【问题标题】:Faster alternatives to .Distinct().Distinct() 的更快替代方案
【发布时间】:2011-05-11 21:43:04
【问题描述】:

我正在制作一款性能至关重要的视频游戏。

我正在使用 .Distinct() 扩展方法从列表中获取唯一值。 有更快的方法吗? (即使这意味着有更多的代码行)

【问题讨论】:

  • 拥有更多背景知识会有所帮助...
  • 您需要更多详细信息 - 您可以控制列表的生成方式吗?如果你一开始就没有在列表中插入重复的元素,你会做得更好......
  • .Distinct 更快。你有简介吗?
  • 游戏性能有很多方面。例如,Distinct 非常快,但它也会产生垃圾。而在 XBOX 版本的框架上,垃圾用于垃圾收集,它可以暂停更新 UI 的线程。我对 Distinct 的担忧不是它的时间成本小,而是它在收集压力方面的巨大成本。您能否更详细地描述一下您的性能预算,包括内存和时间?

标签: c# .net linq


【解决方案1】:

.Distinct 是一个O(n) 电话。
没有比这更快的了。

但是,您应该确保您的 GetHashCode(以及在较小程度上,Equals)尽可能快。

根据您的情况,您可以将List<T> 替换为HashSet<T>,这将首先防止重复插入。 (还有O(1) 插入)

但是,总是先分析您的代码,然后再得出需要更快的结论

【讨论】:

  • +1 表示“总是先分析你的代码,然后再得出关于什么需要更快的结论”
【解决方案2】:

必须是列表吗?

是否可以从 List 切换到 HashSet? HashSet 一开始就防止对象被多次插入到列表中,所以 Distinct 已经完成了。

【讨论】:

    【解决方案3】:

    如果您可以就地执行不同的操作,您可以通过首先使用 Array.Sort 然后非常快速地完成零分配:

     TSource oldV = source[0];
     int pos = 1;
     for (int i = 1; i < source.Count; i++)
     {
         var newV = source[i];
         source[pos] = newV;
         if (!eqComparer.Equals(newV, oldV))
         {
            pos++;
         }                
         oldV = newV;
     }
     //pos now == the new size of the array
    

    然后您必须跟踪现在较小的数组大小,或使用 Array.resize(但这会分配一个新数组)

    或者,如果您使用List&lt;T&gt; 执行相同的方法,您可以在最后调用RemoveRange 来调整它的大小而不进行分配。这最终会明显更快。

    其他海报可能是正确的,尽管您可以通过其他方式实现此目标,例如首先使用哈希集,或者保留一个始终只包含不同元素的并行集合。抵消插入/删除的小成本,因此根本不需要时间来获得不同的集合。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-12-11
      • 2012-07-05
      • 2012-01-23
      • 2013-07-13
      • 2011-02-27
      • 2010-09-22
      • 2017-05-15
      相关资源
      最近更新 更多