【问题标题】:Why is there no Dictionary.TrimExcess()?为什么没有 Dictionary.TrimExcess()?
【发布时间】:2010-12-10 03:42:10
【问题描述】:

在 .NET 中,Dictionary<TKey, TValue> 有一个构造函数,它采用一个参数 int capacity。这与List<T>Queue<T>Stack<T> 等许多其他集合相同;另外,根据the MSDN documentation

字典的容量是在需要调整大小之前可以添加到字典中的元素数。随着元素被添加到字典中,容量会根据需要通过重新分配内部数组来自动增加。

在我看来,这与 List<T> 等其他集合几乎相同。由于这些集合在必要时具有自动调整大小的行为,因此可能具有比所需更大的容量,因此它们中的大多数都具有 @ 987654329@ 方法。例如,如果您一次向集合中添加未知数量的项目,然后您将不再添加任何其他项目,这将非常方便。

为什么Dictionary<TKey, TValue> 没有同样的TrimExcess 方法?

(免责声明:我非常熟悉“默认情况下不存在功能”的响应;我想我主要是想知道TrimExcessDictionary 没有意义是否有特殊原因,或者为什么它比 List 等更简单的集合更难实现。)

【问题讨论】:

  • 由于HashSet 有一个TrimExcess 方法并且在内部也可以使用一个HashTable,我认为没有技术上的理由不为Dictionary 实现TrimExcess。他们甚至在文档中说HashSet 就像没有值的Dictionary
  • 似乎与实现有关,因为 .NET Core 2.1 有 TrimExcess() docs.microsoft.com/en-us/dotnet/api/…
  • 假设 Microsoft 在 .NET Framework 2.0 中首次亮相时故意没有将 TrimExcess 方法添加到 Dictionary<K,V>,因为 .NET Framework 1.1 的 System.Collections.Hashtable也没有类似的方法。调整 List<T>/vector<T>T[] 数组的大小是微不足道的(因为现有的项目索引保持不变,所以简单的分配和复制工作正常),但调整哈希表的大小更困难,因为实际的哈希键需要根据负载因子重新计算。扩大哈希表的内部存储桶数组比缩小它更安全(由于冲突解决)。
  • ...所以我认为 Microsoft 打算 开发人员通过替换并重新填充整个 Dictionary 对象而不是允许来“缩小”Dictionary<K,V>要在内部调整大小的存储桶数组。

标签: .net collections dictionary


【解决方案1】:

到 2019 年,.Net Standard 2.1+ 和 .Net Core 2.1+ 实现Dictionary<TKey, TValue>.TrimExcess()

见:https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2.trimexcess?view=netstandard-2.1

.Net Framework 没有在任何版本中实现它。

【讨论】:

    【解决方案2】:

    我猜在这种情况下,容量参数有助于定义散列函数以及存储桶的数量;调整/修剪稀疏的数据集合需要重新计算所有剩余存储项目的哈希值。

    【讨论】:

    • 其实他们通过GetHashCode()使用Key对象的hashcode,去掉最高位。然后他们将其存储在数组中length % hash 的剩余部分的某个位置(直到找到一个空闲位置)。当然,哈希码的计算是依赖于 key-class 的。
    • 更详细的技术细节,Dictionary 使用“buckets[key.getHashCode() % buckets.Length] = value”来选择放置项目的存储桶。更改存储桶列表的长度需要将所有值移动到新存储桶。
    • @Juliet:差不多。在需要时调整存储桶的大小,并在此过程中复制整个条目列表并重新计算索引,从而重新定位对象。
    【解决方案3】:

    这部分是猜测:字典被“排序”为哈希表。保留的容量不仅仅是字典顶部的一堆空闲内存地址。相反,它由整个字典中的空房间组成。这样做是为了使添加/移动/删除等非常有效。如果您有一个 TrimExcess Dictionary 方法,则整个 Dictionary 必须将所有内容复制到一个新位置,并且元素之间没有任何间隙。

    实际上:间隙应该保留,否则哈希表的好处将失效,修剪 (TrimExcess),如果实施,应该只修剪内部 ValueCollection

    更新:扩展并更改了我的错误选择
    更新:the BCL team says TrimExcess for Dictionaries "could be useful"
    更新:功能请求解决为无法修复:“很遗憾,我们将无法在 .NET 的下一个版本中解决此问题,因此我将其解决为无法修复。”

    【讨论】:

    • 字典没有排序——它被实现为一个哈希表。有序的等价物是 SortedDictionary。
    • 我知道,它不是这样排序的,它是作为哈希排序的。抱歉,如果不清楚
    【解决方案4】:

    Per MSDN Dictionary 被实现为一个哈希表。如果您修剪多余的部分,您将不得不提出一种算法,该算法仍然提供接近 O(1) 的查找时间,而这实际上是一个随机排序的列表。

    【讨论】:

    • O(1) 查找与 TrimExess 有什么关系? O(n) 中的 HashSet.TrimExess。
    【解决方案5】:

    实际上是我要求微软实施 TrimExcess。 我已经发表了不止一篇关于字典的文章,并且在所有情况下我都实现了 TrimExcess。实际上,当桶太小时使用的 Resize 可以在增加或减少桶的大小时调用。

    今天刚发了一篇文章,是一个字典的C++实现,支持TrimExcess: http://www.codeproject.com/Articles/761040/A-NET-like-Dictionary-in-Cplusplus

    可以在本文中找到另一个实现 (.NET): http://www.codeproject.com/Articles/548406/Dictionary-plus-Locking-versus-ConcurrentDictionar

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-11-24
      • 2015-06-20
      • 2014-09-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多