辞書とリスト


30

それで私はDictionary<int, int>今日仕事に出くわしました。おそらくList<int>代わりにa を使用したので、これは私には奇妙に思えました。違いはありますか?一方の構造がもう一方の構造よりも優先されるユースケースがありますか?


1
2つ(またはそれ以上)のintの間に関係が必要ですか?次に、マップ(この言語の辞書)が意味をなします。
リグ

3
名前辞書は私にそれを明らかにします。すばやく調べる必要がある場合は、辞書を使用します。
ChaosPandion

2
@ChaosPandion:List<T>.NETフレームワーク内のルックアップ動作は、典型的には、ランダム・アクセス・アレイであり、高速の場合よりDictionary<int,T>
Doc Brown

2
@DocBrown-数値インデックスをキーとして使用するという奇妙な場合のみ。他の賢明な方法を使用するとルックアップが速くなりDictionary<TKey, TValue>ます。
ChaosPandion

2
@chaosこの質問はその奇妙なケースに関するものです。
MarkJ

回答:


32

Dictionary<int, int>インデックスが位置の配置だけでなく特別な意味を持つ場合は、aを使用します。

頭に浮かぶ直接的な例は、id列とint列をデータベースに格納することです。たとえば、[person-id]列と列がある場合[personal-pin]、それらをに入れることができますDictionary<int, int>。この方法でpinDict[person-id]PINを取得できますが、インデックスは、の位置だけでなく、意味のあるものList<int>です。

しかし、実際には、整数の2つの関連リストがある場合はいつでも、これは適切なデータ構造になる可能性があります。


person-idの範囲が0、...、999であり、個人のピン値を1000人すべてのメモリにロードする必要がある場合、通常List<int>は辞書ではなくを選択します。以下の私の答えをご覧ください。
Doc Brown

3
はい、しかし辞書はまばらかもしれません
jk。

@jk:それがまさに私の答えで詳しく述べようとしたものです。
Doc Brown

7
個人ピン?ちょっと冗長に聞こえます。
ジャック

うーん、インデックスが「特別な意味」を持っている場合、現実世界のシナリオでは、連続した範囲[0、...、n]を形成しない可能性があります(これは必須ではありません)ので、この答えは明白な間違いではなく、不正確です。それにもかかわらず、私見では、決定はこの「特別な意味のもの」に基づくべきではなく、「キーはおよそ間隔[0、...、n]を構築する」にのみ基づいているべきです。賛成票の数に基づいて、私はほとんどの読者がその点を見逃したと思います。
Doc Brown

28

List配列Dictionaryハッシュテーブルと考えてください。Dictionary意味のあるキーを値にマップ(または関連付け)する必要がある場合にのみ使用しますが、List位置(またはインデックス)を値にマップ(または関連付け)するだけです。

たとえば、人の年齢と身長との関連付けを保存するとします。a Dictionary<int, int>を使用して、人の年齢(an int)を身長(an int)にマッピングできます。

Dictionary<int, int> personHeightMap = new Dictionary<int, int>();

personHeightMap.Add(21, 185);
personHeightMap.Add(31, 174);

int height = personHeightMap.ContainsKey(21) ? personHeightMap[21] : -1;

非常に有用な例ではありませんが、ポイントはListこれらの値を位置的に保存する必要があるため、これをエレガントに行うことはできません。


7
+1は注文をList扱っていることに言及するためにあり、ここでは協会をDictionary扱ってます。毎回特定の順序でデータを取得する必要がある場合、または相互に関連する順序が重要な場合Listは、a を使用する方法です。Dictionaries順序付けられていない傾向があり、マッピングキー->値の関係を扱います。
KChaloux

2
最後に重要なことは、探しているものがわかっている場合、ハッシュテーブルはO(1)時間前後であり、配列は最適なケースではO(logN)(ソート済みおよび重複なし)およびO(N)最悪の場合。
JensG 14

1
+1。私の意見では、リストが意味的に順序付けられ、ディクショナリが意味的に検索されるという点については、絶対に基本的なことは誰も扱っていないようです。
ベンジャミンホジソン14

15

意味的に、Dictionary<int, T>List<T>は非常によく似ており、どちらも.NETフレームワークのランダムアクセスコンテナーです。リストをディクショナリの代わりとして使用するには、リスト内の空のスロットを表す特別な値T(などnull)が必要です。Tがのようなnull許容型でない場合はintint?代わりに使用できます。または、正の値を格納するだけの場合は、-1のような特別な値を使用して空のスロットを表すこともできます。

どちらを選択するかは、キー値の範囲によって異なります。のキーがDictionary<int, T>整数の間隔内にあり、それらの間に多くのギャップがない場合(たとえば、[0、... 100]から80の値)、List<T>インデックスによるアクセスが高速であるため、aの方が適切です。この場合、辞書に比べてメモリと時間のオーバーヘッドが少なくなります。

キー値がint[0、...、1000000]のような範囲の100個の値であるList<T>場合、Tの1000000個の値を保持するためにメモリが必要です。ただし、辞書にはTの約100個の大きさのメモリが必要です。 intの100個の値(さらにいくつかのオーバーヘッド。実際には、これらの100個のキーと値を格納するためのメモリの約2倍を想定しています)。後者の場合、辞書がより適切になります。


6
これは、imhoの重要な違いです。Dictionary<int、int>はスパースにすることができます
jk。

その場合、List <KeyValuePair <int、int >>を使用できませんか?どちらが線形トラバーサルに適していますか?
ディーパックミシュラ

@DeepakMishra:ここでの主な違いは、ではList<KeyValuePair<int,T>>、利用可能なO(1)ルックアップ操作がないことです。第二に、の要素はList<KeyValuePair<int,T>>キー値とは無関係に特定の順序を持​​つことができます。前者ではなく後者が必要な場合、List<KeyValuePair<int,T>>またはList<Tuple<int,T>>より良い選択である場合があります。両方が必要な場合もありOrderedDictionaryます。
ドックブラウン

@DocBrownリニアトラバーサル(つまりforeach)と挿入操作に適しているのは、直接検索する必要のないものでしょうか。
ディーパックミシュラ

@DeepakMishra:ソフトウェア開発には「一般的に良い」ようなものはありません。ここで良いとは、より速く、読みやすく、入力するコードが少なく、今後の要件に合わせて簡単に拡張できることを意味します。しかし、一般的には、これを考え直すのをやめ、手元の問題を正しく解決し、あなたの目で最も簡単なものを実装し、目的に十分な速さかどうかを確認し、欠点を観察するときにそれ以上の考えだけを投資してください。
Doc Brown

6

誰もがそれらを同等とみなすことができますか?

辞書はスパースでランダムな挿入を許可しますが、順序のトラバースを問題にします。リストはスパースではなく、順序のない挿入は高価であり、本質的に順序のトラバーサルを提供します。

一方が他方より劇的に優れていない状況はほとんどありません。


2

余談:他のプログラミング言語は、このタイプのデータ構造を辞書ではなくマップと呼びます。

データをキー/値ペアとして有意義に定義できる場合、そのキーを使用して値を見つける必要がある場合、ディクショナリははるかに高速なアクセスを提供します。

たとえば、顧客のリストがあるとします。各顧客には、名前や住所、一意の顧客番号などの詳細が含まれます。処理中の注文のリストもあるとします。各注文には何が行われているかの詳細が含まれ、注文した人の顧客番号を含める必要があります。

注文の発送準備が整ったら、発送先の住所を見つける必要があります。顧客がプレーンリストとして保存されている場合は、リスト全体を検索して、適切な顧客番号を持つ顧客を見つける必要があります。代わりに、顧客番号をキーとして、顧客を辞書に保存できます。辞書を使用すると、検索せずに1つのステップで正しい顧客を引き出すことができます。


1

辞書はハッシュを使用してデータを検索します。辞書が最初にキーのハッシュ値を計算し、このハッシュ値がターゲットデータバケットにつながります。その後、バケット内の各要素が等しいかどうかを確認する必要があります。しかし実際には、最初のステップで検索するものがないため、リストは最初のアイテム検索の辞書よりも高速になります。ただし、2番目のステップでは、リストは最初の項目を調べてから、2番目の項目を調べる必要があります。そのため、検索の各ステップにはますます時間がかかります。リストが大きいほど、時間がかかります。

.... 辞書とリストの例の詳細。


-1

問題のコードが相関値の2つのセットを格納している場合、Dictionaryクラスはキーによって値を検索するインデックス付きの方法を提供します。そこ値の一組だけですが、そのセットがランダムにアクセスする必要がある場合(おそらくセットでキーの存在を確認するために)、および値が一意である、HashSetのは、使用するのに最適なセットクラスかもしれません。


-3

これらは、ベースをカバーしているように見える素晴らしい答えです。

私が提供するもう1つの考慮事項は、コーディングの観点から(C#の)辞書がより複雑であることです。リストとディクショナリの両方を同じコードベースに含めると、オブジェクトデータの検索やマーシャリングなどの基本的な操作の方法が微妙に異なるため、コードのメンテナンスが難しくなります。私の見方では、正当な理由で辞書が必要でない限り、リストを使用します。


8
同意しません。辞書/マップは、すべてのソフトウェアエンジニアが熟知している必要がある基本的なデータ構造です。いずれにしても、データ構造を使用する正当な理由が必要です。リストを含む。
スティーブンエバーズ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.