【发布时间】:2010-11-30 00:07:57
【问题描述】:
我了解字典不是有序集合,不应依赖于字典中插入和检索的顺序。
但是,这是我注意到的:
- 向字典中添加了 20 个键值对
- 通过执行 foreach(KeyValuePair...) 检索它们
检索顺序与添加顺序相同。 测试了大约 16 个键值对。
这是设计的吗?
【问题讨论】:
标签: c# .net collections
我了解字典不是有序集合,不应依赖于字典中插入和检索的顺序。
但是,这是我注意到的:
检索顺序与添加顺序相同。 测试了大约 16 个键值对。
这是设计的吗?
【问题讨论】:
标签: c# .net collections
来自MSDN:
出于枚举的目的,字典中的每个项目都被视为一个
KeyValuePair<(Of <(TKey, TValue>)>)结构,表示一个值及其键。 物品返回的顺序未定义。
[强调添加]
【讨论】:
我不这么认为,字典并没有授予其中项目的内部排序。 如果您还需要保持顺序,请使用附加数据结构(数组或列表)以及字典。
【讨论】:
这是巧合,尽管可以预见。你绝对不应该依赖它。通常它会发生在简单的情况下,但是如果您开始删除元素并用具有相同哈希码或只是进入相同存储桶的任何内容替换它们,该元素将占据原始元素的位置,尽管添加的时间比其他人晚。
重现这个相对繁琐,但我不久前设法做到了for another question:
using System;
using System.Collections.Generic;
class Test
{
static void Main(string[] args)
{
var dict = new Dictionary<int, int>();
dict.Add(0, 0);
dict.Add(1, 1);
dict.Add(2, 2);
dict.Remove(0);
dict.Add(10, 10);
foreach (var entry in dict)
{
Console.WriteLine(entry.Key);
}
}
}
结果显示 10, 1, 2 而不是 1, 2, 10。
请注意,如果您不执行任何删除操作,即使 当前 行为看起来总是按插入顺序生成元素,但不能保证未来的实现也会这样做......所以即使在您知道不会删除任何内容的受限情况下,也请不要依赖于此。
【讨论】:
String 作为键时,它表现出ImmutableDictionary 枚举的不确定性.这提供了一个示例,现在 current 行为不会按插入顺序产生元素(尽管对于 ImmutableDictionary)。
我相信枚举Dictionary<K,V> 将按照它们插入的顺序返回键如果所有键散列到相同的值。这是因为Dictionary<K,V> 实现使用键对象的哈希码将键/值对插入到桶中,并且值(通常)按照插入的顺序存储在桶中。如果您在用户定义的对象中一直看到这种行为,那么您可能没有(正确地)覆盖GetHashCode() 方法?
【讨论】:
根据设计,Dictionary<TKey,TValue> 不是有序结构,因为它主要用于更多基于密钥的访问。
如果您需要按特定顺序检索项目,您应该查看Sorted Dictionary<TKey, TValue>,它采用Comparer<T>,用于对Sorted Dictionary<TKey, TValue> 中的键进行排序。
【讨论】:
如果您想以固定顺序遍历字典,您可以尝试OrderedDictionary
【讨论】:
这是设计使然吗?它可能不在最初的 .Net Framework 2.0 中,但现在有一个隐含的约定,它们将按照添加的顺序进行排序,因为改变它会破坏很多依赖于原始泛型行为的代码字典。与 Go 语言相比,他们的地图故意返回随机排序,以防止地图用户依赖任何排序 [1]。
框架编写者对 Dictionary<T,V> 所做的任何改进或更改都必须保留该隐式契约。
[1] "自 Go 1.0 发布以来,运行时地图迭代顺序随机化。", https://blog.golang.org/go-maps-in-action .
【讨论】: