【问题标题】:In C#, is there a way to create a List directly from an Array without copying?在 C# 中,有没有办法直接从数组创建列表而无需复制?
【发布时间】:2018-09-25 18:54:42
【问题描述】:

C# 是否提供了一种直接从数组创建列表而无需逐个复制元素的方法?

我知道在底层,列表只是维护一个数组,因此从一个数组开始并创建一个新列表在内部简单地指向该数组似乎很自然。这样做的好处是在将数组转换为 List 时会大大提高性能。

在 C# 中是否有本地方法可以做到这一点?如果没有,是否有人有扩展方法或库来执行此操作?

Peter 要求量化“性能的巨大提升”。 所以这里是基于我对 List 构造函数如何工作的理解:

List() 包含三个重载。其中一个重载将 IEnumerable 作为输入。这种重载通过声明一个非常小的新列表来工作(除非它在最近的 c# 版本中发生了变化,历史默认大小为 0,然后在首次添加元素时初始化为 4)。

每次将一个元素添加到列表中时,如果新元素超出容量,则通过创建一个全新的数组并将元素一个接一个地复制到新数组,数组大小会增加一倍。这样做的结果是,从 IEnumerable 构建 List 的成本是 O(n) 加上所有发生的数组副本的成本。重点是,不小。

对于 IEnumerable,List() 构造必须以这种方式工作,因为 IEnumerable 的大小未知。如果你从一个数组创建一个 List,你会在创建时知道确切的大小,这意味着成本应该是 O(1)。

【问题讨论】:

  • 请量化“性能上的巨大提升”。在大多数情况下,这似乎是过早的优化。
  • 接受数组的 List 构造函数将调用 Array.Copy。我怀疑这会 blit 整个数组,而不是一个一个地枚举和复制。
  • 如果你愿意做一些性能测试,你可能会发现像 var newList = new List(theArray.Length); newList.AddRange(theArray); 这样的东西要快一些(不过,谁知道呢,这可能是 System.Array.ToList 在幕后所做的
  • 我对这个问题有点困惑——List<T> 构造函数是否一个接一个复制项目是一个实现细节。当给定一个数组作为参数时,列表构造函数从旧数组调用CopyTo 到新数组,它也应该这样做。 CopyTo 是如何工作的——无论是一次复制一个项目,还是将它们分批以利用处理器同时复制多个小项目的能力——又是一个实现细节。但该代码应该非常快
  • 我不认为这是一个愚蠢的问题;我确实认为数组几乎从来都不是满足我需求的数据结构,这正是您引用的原因!数组是我不想要的大小固定但内容可变的奇怪组合。十年前我写了一篇关于这个主题的博客文章。 blogs.msdn.microsoft.com/ericlippert/2008/09/22/…

标签: c# arrays list


【解决方案1】:

不,因为 List 对象需要能够控制数组。如果您有对 List 之外的数组的引用,它将失去该保证。

【讨论】:

  • 我现在觉得很可笑。大声笑谢谢,乔尔。 :)
【解决方案2】:
  1. 您可能不需要额外的性能,如果您的应用遇到性能问题,从数组转换为列表可能不是罪魁祸首。
  2. 如果它罪魁祸首,并且如果你确实需要性能,你应该首先尝试重构你的代码,这样你不需要 经常从数组转换为列表。
  3. 非常不太可能的情况下,您确实需要它,如果您真的有抱负,您可以创建自己的 IList<T> 并添加你的数组。

所以你会得到类似的东西

public class CustomList<T> : IList<T>, ICollection<T>, IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>, IEnumerable<T>, IEnumerable
{
    public CustomList (T[] array)
    {
        //insert implementation here
    }
    // insert implimentation here
}

注意:这样做所获得的假定性能提升可能不值得花时间来实现这个类,更不用说在实现新 List 时犯一些错误的风险。如果您必须在 Stack Overflow 上提出这样的问题,您可能没有足够的经验来制作比 Microsoft 更好的 IList&lt;T&gt;

【讨论】:

    猜你喜欢
    • 2018-10-13
    • 1970-01-01
    • 2011-10-05
    • 2021-08-30
    • 2013-11-27
    • 1970-01-01
    • 2019-08-26
    • 2019-04-24
    • 1970-01-01
    相关资源
    最近更新 更多