如果词典的内容完全相同,那么它的顺序是否相同?

时间:2011-01-24 18:03:28

标签: c# .net dictionary

我知道字典的顺序是未定义的,MSDN这样说:

  

出于枚举的目的,字典中的每个项都被视为表示值及其键的KeyValuePair结构。返回项目的顺序未定义。

多数民众赞成,但如果我有两个字典实例,每个实例都有相同的内容,那么订单是否相同?

我猜是这样的,因为据我所知,顺序是由键的哈希决定的,如果两个词典具有相同的键,它们具有相同的哈希值,因此顺序相同...

......对吗?

谢谢!

安迪。

6 个答案:

答案 0 :(得分:9)

不能保证不是同一个订单。想象一下,在Dictionary<TKey, TValue>中有几个具有相同哈希码的项目的情况。如果它们以不同的顺序添加到两个词典中,则会导致枚举中的顺序不同。

例如考虑以下(符合相等性)代码

class Example
{
    public char Value;
    public override int GetHashCode()
    {
        return 1;
    }
    public override bool Equals(object obj)
    {
        return obj is Example && ((Example)obj).Value == Value;
    }
    public override string ToString()
    {
        return Value.ToString();
    }
}

class Program
{
    static void Main(string[] args)
    {
        var e1 = new Example() { Value = 'a' };
        var e2 = new Example() { Value = 'b' };
        var map1 = new Dictionary<Example, string>();
        map1.Add(e1, "1");
        map1.Add(e2, "2");

        var map2 = new Dictionary<Example, string>();
        map2.Add(e2, "2");
        map2.Add(e1, "1");

        Console.WriteLine(map1.Values.Aggregate((x, y) => x + y));
        Console.WriteLine(map2.Values.Aggregate((x, y) => x + y));
    }
}

运行此程序的输出是

12
21

答案 1 :(得分:4)

简短版:否。

长版:

    [TestMethod]
    public void TestDictionary()
    {
        Dictionary<String, Int32> d1 = new Dictionary<string, int>();
        Dictionary<String, Int32> d2 = new Dictionary<string, int>();

        d1.Add("555", 1);
        d1.Add("abc2", 2);
        d1.Add("abc3", 3);
        d1.Remove("abc2");
        d1.Add("abc2", 2);
        d1.Add("556", 1);

        d2.Add("555", 1);
        d2.Add("556", 1);
        d2.Add("abc2", 2);
        d2.Add("abc3", 3);

        foreach (var i in d1)
        {
            Console.WriteLine(i);
        }
        Console.WriteLine();
        foreach (var i in d2)
        {
            Console.WriteLine(i);
        }
    }

输出:

[555, 1]
[abc2, 2]
[abc3, 3]
[556, 1]

[555, 1]
[556, 1]
[abc2, 2]
[abc3, 3]

答案 2 :(得分:3)

如果MSDN说它未定义,你必须依赖它。未定义的东西是它意味着允许字典的实现以它想要的任何顺序存储它。这意味着程序员不应该对订单做任何假设。我可能会假设个人没有看到字典中元素的顺序将取决于他们进入的顺序,但我可能是错的。无论答案是什么,如果你想要一些行为,两个订单都是相同的那么你就是做错了。

答案 3 :(得分:1)

  

“如果两个词典有相同的话   钥匙,他们有相同的哈希,和   因此订单相同......“

我不认为是这种情况。即使它可能是真的,我也不会依赖于此。如果确实这是一个实现细节,可能会改变,或者在CLR或BCL的不同实现上有所不同(Mono浮现在脑海中)。

Microsoft Dictionary实现有点复杂,但从查看代码5分钟后,我愿意猜测枚举的顺序将基于字典如何当前州,包括调整大小和插入顺序的数量。

答案 4 :(得分:1)

如果规范说订单是“未定义”,则不能在没有明确订购的情况下依赖订单。可以随时使用新版本或Service Pack更改底层实现,仅适用于初学者。您的词典也可能来自任何数量的具体实现。

底层实施可能对所应用的操作顺序敏感。按顺序添加键“a”,“b”和“c”可能会导致与以不同顺序添加同一组键(例如,'b','c'和'a')不同的数据结构)。删除可能同样会影响数据结构。

例如,直接二进制树,如果用作字典后面的数据结构,如果按顺序添加键,则净结果是高度不平衡的树,本质上是链表。如果以随机顺序插入节点,树将更加平衡。

并且一些数据结构在执行操作时变形。例如,如果字典是在底层数据结构为红色/黑色树的情况下实现的,则树节点将被分割/旋转,以便在插入和删除发生时保持树平衡。因此,即使最终内容相同,实际的数据结构也高度依赖于操作的顺序。

答案 5 :(得分:0)

我不知道微软实现的具体细节,但一般来说,只有当字典中没有两个项目散列到相同的值或者那些碰撞的条目以相同的顺序添加时,你的假设才会成立。