辞書に追加するさまざまな方法


107

違いは何ですかDictionary.add(key, value)とはDictionary[key] = value

ArgumentException重複キーを挿入するときに最後のバージョンではがスローされないことに気付きましたが、最初のバージョンを優先する理由はありますか?

編集:これに関する信頼できる情報源はありますか?私はMSDNを試しましたが、それはいつものように野生のガチョウの追跡です:(

回答:


109

パフォーマンスはほぼ100%同一です。これは、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の場合、例外をスローします。

したがって、すべての目的と意図でパフォーマンスは同じです。

他のいくつかの言及と同様に、同じキーを2回追加しようとする試みについて、チェックが必要かどうかがすべてです。

投稿が長かったため申し訳ありませんが、それでいいと思います。


+1非常に興味深い、投稿ありがとうございます。他のポスターが示唆しているように、パフォーマンスはほぼ同じであるように思われますが、とにかく素晴らしい発見です:)
Sune Rievers

70

最初のバージョンは、新しいKeyValuePairをディクショナリに追加し、キーがすでにディクショナリにある場合にスローします。2番目は、インデクサーを使用して、キーが存在しない場合は新しいペアを追加しますが、キーが辞書に既に存在する場合はキーの値を上書きします。

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上記の情報源を入手しましたか?最初のフォームまたは後者のフォームを使用する際に副作用や注意点があるかどうかを知りたいです。
Sune Rievers、2009

3
他のコメントで言及されている以上に、ソースが本当にあるわけではありません。私が正しく覚えている場合、追加はインデクサーを使用するだけですが、まずキーが既に使用されているかどうかを確認します。
hhravn 2009

1
ドキュメントが一流であるため、Steffen'sへの受け入れられた回答を変更しました。これはまだ素晴らしい答えです。
Sune Rievers、2009

@Sune:悪い動き...個人的に私はこの答えはSteffenの前にある通りだと思います...端的に言ってまともな例です。
demoncodemonkey 2010

1
@SuneRievers私が思うに、現在受け入れられている答えではなく、受け入れられた答えの場合、それは人々にとってより助けになるでしょう。これは、(パフォーマンスについて話している)受け入れられた質問(および私と同じようにこのトピックを検索するユーザーのほぼ99%)ではなく、質問(「違いは何ですか」)に正確に答えるため、「違い」が必要だった(なぜこれに会ったのか)トピック)、そして受け入れられた答えは私にとって役に立たず、2番目を無駄にします。代わりに、この答えは正確です
T.Todua

30

Dictionary.Add(key, value)そしてDictionary[key] = value異なる目的があります:

  • Addメソッドを使用して新しいキー/値ペアを追加します。既存のキーは置き換えられません(ArgumentExceptionスローされます)。
  • ディクショナリにキーが既に存在するかどうかを気にしない場合は、インデクサーを使用します。つまり、キーがディクショナリにない場合はキーと値のペアを追加するか、キーがすでにある場合は指定したキーの値を置き換えます辞書で。

1
意図を自己記述したコードは重要であり、非常に価値があります(コメントをほとんどまたはまったく必要としません)。この回答は、両方の方法の意図の違いを示しており、どちらを選択するかに従う必要があります。あなたは換言すれば、「インデクサの追加」を使用していない事前に知っているあなたは常に追加されます、あるいはことを必ずしなければならない追加します。IndexOutOfBounds例外がスローされることは、予期しない動作よりも優れています。
ryancdotnet 2018

28

最初にこの質問に答えるには、辞書の目的と基礎となるテクノロジーを確認する必要があります。

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");

定義には2つの可能性があります。以前に存在しなかったものに新しい定義を与えるか、またはすでに存在する定義を変更したいかのいずれかです。

Addメソッドを使用すると、レコードを追加できますが、この定義のキーは辞書に存在しない可能性があります。

次に、内部を調べます。辞書を作成するとき、コンパイラはバケット(レコードを格納するためのメモリ内のスペース)を予約します。バケットは、定義した方法でキーを保存しません。各キーはバケット(Microsoftが定義)に移動する前にハッシュされます。値の部分は変更されないことに注意してください。

私の例を簡略化するために、CRC32ハッシュアルゴリズムを使用します。定義するとき:

myDietFavorites[0] = "Pizza";

バケットに送られるのdb2dc565 "Pizza"(簡略化)です。

で値を変更すると:

myDietFavorites[0] = "Spaghetti";

再びdb2dc565である 0をハッシュしてから、バケットでこの値を検索して、そこにあるかどうかを確認します。そこにある場合は、キーに割り当てられた値を書き換えるだけです。そこにない場合は、値をバケットに入れます。

次のように辞書でAdd関数を呼び出すと、

myDietFavorite.Add(0, "Chocolate");

0をハッシュして、その値をバケット内の値と比較します。そこにない場合にのみ、バケットに入れることができます。

文字列または文字タイプのキーの辞書を操作する場合は特に、それがどのように機能するかを知ることが重要です。ハッシュが行われるため、大文字と小文字が区別されます。したがって、たとえば "name"!= "Name"です。これを表すためにCRC32を使用してみましょう。

「名前」の 値は:e04112b1「名前」の値は:1107fb5b


この2行で十分理解できます.......定義には2つの可能性があります。以前に存在しなかったものに新しい定義を与えるか、既存の定義を変更します。Addメソッドを使用すると、レコードを追加できますが、この定義のキーは辞書に存在しない可能性があります。
Niraj Trivedi

4

はい、違います。キーが既に存在する場合、Addメソッドは例外をスローします。

Addメソッドを使用する理由はまさにこれです。ディクショナリにキーが含まれていると想定されていない場合は、通常、例外を確認して問題を認識させます。


0

パフォーマンスの類似性が最も高いと考えられる場合は、使用しているコードに対してより正確で読みやすいと思われるものを使用してください。

追加を説明する操作を感じます。キーが存在することはすでに非常にまれな例外であるため、追加で最もよく表されます。意味的にはもっと理にかなっています。

dict[key] = valueより良い置換を表します。そのコードを見ると、とにかく、キーが既に辞書にあることを期待しています。


最初にキーが存在するかどうかをチェックしないことで、パフォーマンスが少し向上すると思います。dic[key] = valueキーが既に存在しているとは思いませんが、議論の余地があると思います;)
Sune Rievers

2
+スローは、キーがすでに表現されているかどうかを確認する方法として決して使用すべきではないと思います。if(!strings.ContainsKey( "foo"))strings.Add( "foo"、 "bar");
hhravn 2009


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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.