我刚看到这个行为,感到有些惊讶...
如果我向字典中添加3或4个元素,然后使用“For Each”获取所有键,它们出现的顺序与我添加它们的顺序相同。
这让我感到惊讶的原因是,字典内部应该是一个哈希表,所以我期望事情按任何顺序出现(按键的哈希排序,对吗?)
我错过了什么吗? 我可以依赖这种行为吗?
编辑:好的,我已经想到很多可能导致这种情况发生的原因了(例如条目的单独列表,这是否是巧合等)。 我的问题是,有人知道这是如何实现的吗?
我刚看到这个行为,感到有些惊讶...
如果我向字典中添加3或4个元素,然后使用“For Each”获取所有键,它们出现的顺序与我添加它们的顺序相同。
这让我感到惊讶的原因是,字典内部应该是一个哈希表,所以我期望事情按任何顺序出现(按键的哈希排序,对吗?)
我错过了什么吗? 我可以依赖这种行为吗?
编辑:好的,我已经想到很多可能导致这种情况发生的原因了(例如条目的单独列表,这是否是巧合等)。 我的问题是,有人知道这是如何实现的吗?
add 1
add 2
add 3
add 4
remove 2
add 5
因为它重复使用了空槽,所以你将得到1 5 3 4。
需要注意的是,就像许多其他人所说的那样,您不能依赖于未来(或过去)的版本中的这种行为。如果您希望字典被排序,则有一个SortedDictionary类可用于此目的。
不能指望这种行为,但也不足为奇。
考虑如何为简单哈希表实现键的迭代。您需要遍历所有哈希桶,无论它们是否为空。从大哈希表中获取小数据集可能效率低下。
因此,保留一个单独的、重复的键列表可能是一个好的优化方法。使用双向链表仍然可以获得常数时间插入/删除。(您将从哈希表桶中保留一个指针指向此列表。) 这样,通过键列表进行迭代仅取决于条目数量,而不是桶数量。
MSDN 中的一句话:
Dictionary<(Of <(TKey, TValue>)>).KeyCollection中键的顺序是未指定的,但与由Dictionary<(Of <(TKey, TValue>)>).Values属性返回的关联值相同。
你的条目可能都在字典中的同一个哈希桶中。每个桶可能是桶中条目的列表。这可以解释为什么条目按顺序返回。
在某个列表大小范围内,仅检查每个条目而不进行哈希处理更便宜。这可能就是正在发生的事情。
添加100或1000个项目,并查看它们是否仍然按照相同的顺序排列。
我讨厌这种“按设计”功能。我认为,当你给你的类起一个如此通用的名称“Dictionary”时,它也应该表现出“通常的预期”。例如,std::map始终保持其键值排序。
编辑:显然解决方案是使用SortedDictionary,它的行为类似于std::map。
SortedDictionary
的建议假定用户有明确的排序意图。如果您想保证插入顺序被保留,您应该实现自己的IDictionary<TKey, TValue>
实现类。 - James Dunne