添加字典的不同方式


107

是什么在差异Dictionary.add(key, value)Dictionary[key] = value

我注意到,ArgumentException插入重复密钥时,最新版本不会抛出,但是有什么理由偏爱第一版本吗?

编辑:有人对此有权威的信息来源吗?我尝试过MSDN,但它总是像往常一样追逐:(

Answers:


109

性能几乎是100%相同。您可以通过在Reflector.net中打开类来检查

这是This indexer:

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非常有趣,感谢您的发帖!正如其他海报所暗示的那样,此处的表现似乎几乎相同,无论如何都很棒:)
Sune Rievers 2009年

70

第一个版本将向字典添加新的KeyValuePair,如果字典中已存在key则抛出该异常。第二种方法是使用索引器,如果该键不存在,则会添加一个新对,但是如果该键在字典中已经存在,则覆盖该键的值。

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     

+1您是否有上述信息的来源?我有兴趣了解使用第一种或后一种形式是否有任何副作用或警告。
苏恩·里维尔斯

3
真的没有这样的消息来源,就在我头顶上,但我认为没有什么比其他评论中提到的更多。如果我没记错的话,Add只是使用索引器,而是先检查是否已经使用了Key。
hhravn

1
更改了Steffen的已接受答案,因为他的文档是一流的。不过,这仍然是一个很好的答案。
苏恩·里弗

@Sune:不好的举动...我个人认为,这个答案是比Steffen领先的街道...直截了当,这是一个不错的例子。
demoncodemonkey 2010年

1
@SuneRievers我认为,如果为此接受答案,那么对于人们来说将是更多的帮助,而不是当前接受的答案。因为这正好回答了问题(“有什么区别”),而不是被接受的问题(谈论性能,并且几乎有99%的用户在搜索此主题(如我),所以需要这样的问题)(“为什么如此”)主题),和接受的答案是没有用的,我和废物我们的第二个代替,这个答案是准确的。
T.Todua

30

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

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

1
自我描述意图的代码非常重要,而且非常有价值(几乎不需要注释)。此答案显示了两种方法在意图上的差异,选择一种方法时应遵循。换句话说,当您提前知道将始终添加甚至必须始终添加时,请勿使用“索引器添加” 。抛出IndexOutOfBounds异常要比意外行为好。
ryancdotnet

28

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

Dictionary 是的清单 KeyValuePair<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");

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

Add方法允许您添加记录,但只能在一种情况下:此定义的键可能在字典中不存在。

现在,我们将深入研究。当您制作字典时,编译器会为存储区(存储记录的内存空间)预留一个空间。存储桶不会以您定义密钥的方式存储密钥。每个键在进入存储桶(由Microsoft定义)之前都经过哈希处理,值得一提的是值部分保持不变。

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

myDietFavorites[0] = "Pizza";

即将推出的内容是db2dc565 “ Pizza”(简化版)。

当您使用更改值时:

myDietFavorites[0] = "Spaghetti";

您对0进行哈希处理,这又是db2dc565进行然后在存储桶中查找此值以查找是否存在该值。如果在那里,您只需重写分配给键的值。如果不存在,您将把价值放在桶中。

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

myDietFavorite.Add(0, "Chocolate");

您对0进行哈希处理,以将其值与存储桶中的值进行比较。仅当它不在桶中时,可以将其放在桶中。

知道它是如何工作的至关重要,尤其是当您使用字符串字典或键的char类型的字典时。由于要进行哈希处理,因此区分大小写。因此,例如“ name”!=“ Name”。让我们用CRC32来描述这一点。

“名称”的 值是:e04112b1 “名称”的值是:1107fb5b


这两条线足以理解.......定义有两种可能,您要么想要为之前不存在的内容提供新的定义,要么想要更改已经存在的定义。Add方法允许您添加记录,但只能在一种情况下:此定义的键可能在字典中不存在。
Niraj Trivedi

4

是的,区别在于,如果键已经存在,则Add方法将引发异常。

使用Add方法的原因正是这样。如果字典不应该包含该键,则通常需要该异常,以便使您意识到问题所在。


0

鉴于在性能上比大多数(可能)相似,请使用对您正在使用的代码更正确,更易读的内容。

我感觉到一个描述加法的操作,因为键的存在已经是一个非常罕见的例外,所以最好用加法来表示。从语义上讲,这更有意义。

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


我认为不检查密钥是否首先存在会带来很小的性能提升。我不希望dic[key] = value密钥已经存在,但是我想这是有争议的;)
Sune Rievers 2009年

2
+我认为投掷绝不应该用作检查钥匙是否已经被表示的一种方法。if(!strings.ContainsKey(“ foo”))strings.Add(“ foo”,“ bar”);
hhravn


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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.