添加到Dictionary的不同方式

时间:2009-12-03 08:28:09

标签: c# optimization dictionary

Dictionary.add(key, value)Dictionary[key] = value有什么区别?

我注意到最后一个版本在插入重复密钥时没有抛出ArgumentException,但有没有理由更喜欢第一个版本?

编辑:是否有人拥有关于此的权威信息来源?我已经尝试过MSDN,但它一如既往的追逐:(

8 个答案:

答案 0 :(得分:94)

性能几乎完全相同。您可以通过在Reflector.net中打开课程来检查这一点

这是这个索引器:

public TValue this[TKey key]
{
    get
    {
        int index = this.FindEntry(key);
        if (index >= 0)
        {
            return this.entries[index].value;
        }
        ThrowHelper.ThrowKeyNotFoundException();
        return default(TValue);
    }
    set
    {
        this.Insert(key, value, false);
    }
}

这是Add方法:

public void Add(TKey key, TValue value)
{
    this.Insert(key, value, true);
}

我不会发布整个Insert方法,因为它很长,但方法声明是这样的:

private void Insert(TKey key, TValue value, bool add)

在功能中进一步发生这种情况:

if ((this.entries[i].hashCode == num) && this.comparer.Equals(this.entries[i].key, key))
{
    if (add)
    {
        ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_AddingDuplicate);
    }

检查密钥是否已存在,如果密钥已存在且参数add为true,则会抛出异常。

因此,出于所有目的和意图,性能是相同的。

与其他一些提及的一样,关键是你是否需要检查,试图两次添加相同的密钥。

对于冗长的帖子感到抱歉,我希望没关系。

答案 1 :(得分:65)

第一个版本将向字典中添加一个新的KeyValuePair,如果密钥已经在字典中,则抛出。第二个,使用索引器,如果密钥不存在,将添加一个新对,但如果密钥已经存在于字典中,则覆盖密钥的值。

IDictionary<string, string> strings = new Dictionary<string, string>();

strings["foo"] = "bar";          //strings["foo"] == "bar"
strings["foo"] = string.Empty;   //strings["foo"] == string.empty
strings.Add("foo", "bar");       //throws     

答案 2 :(得分:28)

Dictionary.Add(key, value)Dictionary[key] = value有不同的目的:

  • 使用Add方法添加新密钥/值对,不会替换现有密钥(抛出ArgumentException)。
  • 如果您不关心密钥是否已存在于字典中,请使用索引器,换句话说:如果密钥不在字典中,则添加密钥/值对;如果是,则替换指定密钥的值key已经在字典中了。

答案 3 :(得分:21)

首先回答这个问题,我们需要看一下字典和底层技术的目的。

DictionaryKeyValuePair<Tkey, Tvalue>的列表,其中每个值都由其唯一键表示。假设我们列出了您最喜欢的食物。每个值(食物名称)由其唯一键表示(位置=您喜欢这种食物的程度)。

示例代码:

Dictionary<int, string> myDietFavorites = new Dictionary<int, string>()
{
    { 1, "Burger"},
    { 2, "Fries"},
    { 3, "Donuts"}
};

假设你想要保持健康,你已经改变主意,想要用沙拉代替你最喜欢的“汉堡”。您的列表仍然是您的收藏夹列表,您不会更改列表的性质。您最喜欢的将保持在列表中的第一位,只有它的值会改变。这是你打电话的时候:

/*your key stays 1, you only replace the value assigned to this key
  you alter existing record in your dictionary*/
myDietFavorites[1] = "Salad";

但是不要忘记你是程序员,从现在开始你完成你的句子;你拒绝使用表情符号,因为它们会抛出编译错误,所有收藏列表都是0索引。

你的饮食也改变了!所以你再次改变你的清单:

/*you don't want to replace Salad, you want to add this new fancy 0
  position to your list. It wasn't there before so you can either define it*/
myDietFavorites[0] = "Pizza";

/*or Add it*/
myDietFavorites.Add(0, "Pizza");

定义有两种可能性,您要么为之前不存在的内容提供新定义,要么想要更改已存在的定义。

添加方法允许您添加记录但仅在一个条件下:您的字典中可能不存在此定义的键。

现在我们要深入了解一下。当您创建字典时,编译器会对存储区进行预留(内存中的空格用于存储记录)。存储桶不会以您定义它们的方式存储密钥。每个密钥在进入存储桶(由Microsoft定义)之前进行哈希处理,值得一提的是值部分保持不变。

我将使用CRC32哈希算法来简化我的示例。定义时:

myDietFavorites[0] = "Pizza";

桶的内容是 db2dc565 “Pizza”(简化)。

使用以下内容更改值时:

myDietFavorites[0] = "Spaghetti";

你哈希你的0再次 db2dc565 然后你在你的桶中查找这个值来查找它是否在那里。如果它在那里你只需重写分配给键的值。如果它不在那里你就会把你的价值放在桶里。

当您在字典上调用添加功能时:

myDietFavorite.Add(0, "Chocolate");

您散列0以将其值与存储桶中的值进行比较。只有在 时,您才可以将它放在桶中。

了解它是如何工作的至关重要,特别是如果你使用字符串或char类型的键字典。它因为经历散列而区分大小写。例如“name”!=“Name”。让我们用CRC32来描述这个。

“name”的值为: e04112b1 “姓名”的值为: 1107fb5b

答案 4 :(得分:4)

是的,这就是区别,如果密钥已经存在,Add方法会抛出异常。

使用Add方法的原因正是如此。如果字典不应该包含密钥,您通常需要异常,以便您了解问题。

答案 5 :(得分:0)

考虑到性能上可能存在的相似之处,请使用对您正在使用的代码更正确和可读的任何内容。

我觉得一个描述添加的操作,因为密钥的存在已经是一个非常罕见的例外,最好用add来表示。在语义上它更有意义。

dict[key] = value代表更好的替代品。如果我看到那段代码,我一半希望密钥已经在字典中了。

答案 6 :(得分:0)

一个是分配值,而另一个是向Dictionary添加一个新的Key和Value。

答案 7 :(得分:0)

将值插入字典

 Dictionary<string, string> dDS1 = new Dictionary<string, string>();//Declaration
            dDS1.Add("VEqpt", "aaaa");//adding key and value into the dictionary
            string Count = dDS1["VEqpt"];//assigning the value of dictionary key to Count variable
            dDS1["VEqpt"] = Count + "bbbb";//assigning the value to key