23

私はちょうどこの行動を見たばかりで、少し驚いています...

Dictionary に 3 つまたは 4 つの要素を追加し、「For Each」を実行してすべてのキーを取得すると、追加したのと同じ順序で表示されます。

これが私を驚かせた理由は、 Dictionary が内部的に HashTable であると想定されているため、物事が任意の順序で出てくることを期待していたからです (キーのハッシュ順ですよね?)

ここで何が欠けていますか?これは私が信頼できる行動ですか?

編集: OK、私はこれが起こる理由の多くをすでに考えていました(エントリへの別のリスト、これが偶然かどうかなど)。私の質問は、これが実際にどのように機能するか知っている人はいますか?

4

11 に答える 11

41

3.5 クラス ライブラリで .NET Reflector を使用すると、Dictionary の実装によって実際に項目が配列に格納され (必要に応じてサイズが変更されます)、インデックスがその配列にハッシュされることがわかります。キーを取得するとき、ハッシュテーブルを完全に無視し、アイテムの配列を反復処理します。このため、新しい項目が配列の最後に追加されるため、説明した動作が表示されます。次のようにすると次のようになります。

add 1
add 2
add 3
add 4
remove 2
add 5

空のスロットを再利用するため、1 5 3 4 が返されます。

他の多くの人がそうであるように、将来の (または過去の) リリースでこの動作を当てにすることはできないことに注意することが重要です。辞書をソートしたい場合は、この目的のためにSortedDictionaryクラスがあります。

于 2009-06-10T16:54:38.010 に答える
7

ディクショナリは、ハッシュされた順序でアイテムを取得します。挿入順で出てきたのは全くの偶然です。

MSDN のドキュメントには次のように書かれています。

KeyCollection 内のキーの順序は指定されていませんが、Values プロパティによって返される ValueCollection 内の関連付けられた値と同じ順序です。

于 2008-09-30T18:25:02.130 に答える
5

この振る舞いを当てにすることはできませんが、驚くことではありません。

単純なハッシュテーブルのキー反復をどのように実装するかを検討してください。ハッシュバケットに何かが含まれているかどうかに関係なく、すべてのハッシュバケットを反復処理する必要があります。大きなハッシュテーブルから小さなデータセットを取得するのは非効率的です。

したがって、キーの個別の重複リストを保持することは、適切な最適化である可能性があります。二重リンクリストを使用しても、一定時間の挿入/削除が可能です。(ハッシュテーブルバケットからこのリストに戻るポインタを保持します。)このように、キーのリストを反復処理することは、バケットの数ではなく、エントリの数にのみ依存します。

于 2008-09-30T18:31:51.023 に答える
2

これは、「ListDictionary」と「HybridDictionary」の 2 種類の辞書があった古い .NET 1.1 時代に由来すると思います。ListDictionaryは、順序付けられたリストとして内部的に実装された辞書であり、「エントリの小さなセット」に推奨されました。次に、 HybridDictionaryがありました。これは、最初はリストとして内部的に編成されていましたが、構成可能なしきい値よりも大きくなると、ハッシュ テーブルになります。これは、歴史的に適切なハッシュベースの辞書は高価であると考えられていたためです。今ではあまり意味がありませんが、.NET は古い HybridDictionary に基づく新しい Dictionary ジェネリック クラスに基づいているだけだと思います。

:とにかく、他の誰かがすでに指摘しているように、辞書の順序を当てにしてはいけません。

于 2008-09-30T18:34:20.673 に答える
1

エントリはすべて、ディクショナリの同じハッシュバケットにある可能性があります。各バケットは、おそらくバケット内のエントリのリストです。これは、エントリが順番に戻ってくることを説明します。

于 2008-09-30T19:02:58.950 に答える
1

MSDNからの引用:

Dictionary <(Of <(TKey、TValue>)>)。KeyCollection内のキーの順序は指定されていませんが、Dictionary <(Of <(TKey、TValue>)>)内の関連する値と同じ順序です。 Dictionary <(Of <(TKey、TValue>)>)。Valuesプロパティによって返される.ValueCollection。

于 2008-09-30T18:27:46.867 に答える
1

テストでどのキーをどのような順序で追加しましたか?

于 2008-09-30T18:29:27.753 に答える
0

私が知っていることから、これは頼りになる行動であってはなりません。すばやく確認するには、同じ要素を使用して、辞書に追加する順序を変更します。追加された順序でそれらを取り戻すか、それとも単なる偶然であるかがわかります。

于 2008-09-30T18:26:01.583 に答える
0

特定のリストサイズまでは、ハッシュする代わりにすべてのエントリをチェックする方が安価です. それがおそらく起こっていることです。

100 個または 1000 個のアイテムを追加して、それらがまだ同じ順序であるかどうかを確認します。

于 2008-12-09T22:31:40.553 に答える
0

この種の「設計による」機能は嫌いです。クラスに「Dictionary」などの一般的な名前を付けると、「一般的に期待どおり」に動作するはずです。たとえば、 std::map は常にキー値をソートしたままにします。

編集: どうやら解決策は、std::map と同様に動作する SortedDictionary を使用することです。

于 2010-08-11T07:38:10.657 に答える
-1

質問と回答の多くは、ハッシュテーブルまたは辞書の目的を誤解しているようです。これらのデータ構造には、データ構造に含まれる項目の値 (または実際にはキー) の列挙に関して指定された動作はありません。

辞書またはハッシュテーブルの目的は、既知のキーを指定して特定の値を効率的に検索できるようにすることです。ディクショナリまたはハッシュテーブルの内部実装は、ルックアップでこの効率を提供する必要がありますが、値またはキーの列挙または「各」タイプの反復に関して特定の動作を提供する必要はありません。

つまり、内部データ構造は、挿入された順序を含め、必要な方法でこれらの値を格納および列挙できます。

于 2009-05-05T14:52:19.123 に答える