web-dev-qa-db-ja.com

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

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

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

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

91
Sune Rievers

パフォーマンスはほぼ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回追加しようとする場合、チェックが必要かどうかがすべてです。

長い投稿で申し訳ありませんが、大丈夫だと思います。

98
Steffen

最初のバージョンでは、新しい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     
67
hhravn

Dictionary.Add(key, value)Dictionary[key] = valueには異なる目的があります。

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

最初に質問に答えるには、辞書と基礎となる技術の目的を調べる必要があります。

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

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

次のような辞書でAdd関数を呼び出すとき:

myDietFavorite.Add(0, "Chocolate");

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

特に文字列または文字型のキーの辞書を使用する場合は、その仕組みを知ることが重要です。ハッシュ処理のため、大文字と小文字が区別されます。たとえば、「名前」!=「名前」です。 CRC32を使用してこれを説明しましょう。

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

22

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

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

4
Guffa

パフォーマンスのほとんどの類似点を考えると、使用しているコードに対してより正確で読みやすいと思われるものを使用してください。

キーの存在は既に非常にまれな例外であるため、追加を説明する操作を感じます。意味的にはより理にかなっています。

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

0
Jorge Córdoba

1つは値を割り当て、もう1つは辞書に新しいキーと値を追加します。

0
Joshua Smith