回答:
重要なのHashSet<T>
は、名前のすぐそこにあります。それはセットです。単一のセットで実行できる唯一のことは、そのメンバーが何であるかを確立し、アイテムがメンバーであるかどうかを確認することです。
単一の要素(などset[45]
)を取得できるかどうかを尋ねると、セットの概念が誤解されます。セットの45番目の要素のようなものはありません。セット内のアイテムには順序がありません。セット{1、2、3}と{2、3、1}は同じメンバーシップを持っているため、すべての点で同一であり、メンバーシップが重要です。
HashSet<T>
セット内のアイテムに順序を課すため、を反復することはやや危険です。その順序は、実際にはセットのプロパティではありません。あなたはそれに頼るべきではありません。コレクション内のアイテムの順序が重要な場合、そのコレクションはセットではありません。
セットは本当に限られていて、ユニークなメンバーがいます。一方、彼らは本当に速いです。
HashSet
定義されていないので、イテレータの順序に依存しないでください。セット内のアイテムに対して何かを行っているためにセットを反復する場合、注文に関連するものに依存していない限り、それは危険ではありません。A は、プラス注文のすべてのプロパティを持っていますが、から派生していません。言い換えると、SortedSetは個別のオブジェクトの順序付けられたコレクションです。SortedSet
HashSet
SortedSet
HashSet
これが私が使用する実際の例ですHashSet<string>
:
UnrealScriptファイルの構文強調表示機能の一部は、Doxygenスタイルのコメントを強調表示する新機能です。@
または\
コマンドが有効であるかどうかを判断して、それを灰色(有効)で表示するか、赤(無効)で表示するかを決定できる必要があります。私はHashSet<string>
すべての有効なコマンドを持っているので@xxx
、レクサーでトークンをヒットするたびにvalidCommands.Contains(tokenText)
、O(1)有効性チェックとして使用します。有効なコマンドのセット内にコマンドが存在すること以外は何も気にしません。私が直面した代替案を見てみましょう:
Dictionary<string, ?>
:値にはどのタイプを使用しますか?使用するだけなので、値は意味がありませんContainsKey
。注:.NET 3.0より前は、これがO(1)ルックアップの唯一の選択肢でした-3.0 HashSet<T>
で追加されISet<T>
、4.0で実装するように拡張されました。List<string>
:リストを並べ替えたままにしておくと、BinarySearch
O(log n)であるを使用できます(上記の事実がわかりませんでした)。ただし、有効なコマンドの私のリストは変更されない固定リストであるため、これは単により適切ではありません...string[]
:繰り返しますが、Array.BinarySearch
O(log n)パフォーマンスを提供します。リストが短い場合、これが最もパフォーマンスの高いオプションになる可能性があります。それは、常により少ないスペースのオーバーヘッドを持っているHashSet
、Dictionary
またはList
。を使用しても、BinarySearch
大きなセットの方が速くはありませんが、小さなセットの場合は実験する価値があります。鉱山には数百のアイテムがあるので、これを渡しました。A HashSet<T>
はICollection<T>
インターフェースを実装します:
public interface ICollection<T> : IEnumerable<T>, IEnumerable
{
// Methods
void Add(T item);
void Clear();
bool Contains(T item);
void CopyTo(T[] array, int arrayIndex);
bool Remove(T item);
// Properties
int Count { get; }
bool IsReadOnly { get; }
}
List<T>
実装IList<T>
に延び、ICollection<T>
public interface IList<T> : ICollection<T>
{
// Methods
int IndexOf(T item);
void Insert(int index, T item);
void RemoveAt(int index);
// Properties
T this[int index] { get; set; }
}
HashSetにはセマンティクスが設定されており、内部でハッシュテーブルを介して実装されています。
セットは、重複する要素を含まないコレクションであり、その要素には特定の順序はありません。
HashSetがインデックス/位置/リストの動作を失うと、何が得られますか?
HashSetからの項目の追加と取得は、常にインデクサーを介さずにオブジェクト自体によって行われ、O(1)操作に近くなります(リストはO(1)追加、O(1)インデックスによる取得、O(n)検索/削除する)。
HashSetの動作はDictionary<TKey,TValue>
、キーを値として追加/削除するだけで、辞書の値自体を無視することと比較できます。辞書のキーには重複する値がないことが期待されます。それが「セット」部分のポイントです。
リストよりもHashSetを選択するのはパフォーマンスが悪い理由です。代わりに、あなたの意図をよりよく捉えるものは何ですか?順序が重要な場合は、Set(またはHashSet)は無効です。同様に、重複が許可されている場合。しかし、順序を気にしない多くの状況があり、むしろ重複を避けたい-そしてそれはあなたがセットが欲しいときです。
Performance would be a bad reason to choose HashSet over List
:私はあなたに同意しません。つまり、2つのリストではなくDictionrayを選択しても、パフォーマンスは向上しません。見てみましょう次の記事を
string[].Contains
そしてHashSet<string>.Contains
自分の意図も同等に表現します。HashSetを選択する理由は、より高速に実行されるためです。
HashSetは、ハッシュによって実装されるセットです。セットは、重複する要素を含まない値のコレクションです。セット内の値も通常、順序付けされていません。そのため、リストを置き換えるためにセットを使用することはできません(最初にセットを使用する必要がある場合を除きます)。
セットが何に適しているのか不思議に思っている場合:重複を取り除きたい場所なら、明らかに。少し不自然な例として、ソフトウェアプロジェクトの10.000リビジョンのリストがあり、そのプロジェクトに貢献した人の数を調べたいとします。a Set<string>
を使用してリビジョンのリストを反復処理し、各リビジョンの作成者をセットに追加できます。反復が完了すると、セットのサイズが求めていた答えになります。
HashSetは、IEnumerableコレクションの重複要素を削除するために使用されます。例えば、
List<string> duplicatedEnumrableStrings = new List<string> {"abc", "ghjr", "abc", "abc", "yre", "obm", "ghir", "qwrt", "abc", "vyeu"};
HashSet<string> uniqueStrings = new HashSet(duplicatedEnumrableStrings);
これらのコードが実行された後、uniqueStringsは{"abc"、 "ghjr"、 "yre"、 "obm"、 "qwrt"、 "vyeu"}を保持します。
おそらく、ハッシュセットの最も一般的な使用法は、特定の要素が含まれていることを確認することです。これは、包含のチェックがO( n)(およびO(log n)であるソート済みセット)。したがって、多くのチェックを行う場合、アイテムがいくつかのリストに含まれているかどうか、hahssetsはパフォーマンスを向上させる可能性があります。それらを反復するだけの場合、それほど大きな違いはありません(リスト全体と同じようにO(n)が反復され、ハッシュセットはアイテムを追加するときにオーバーヘッドが多少増えます)。
また、セットは順序付けされていないため、セットにインデックスを付けることはできません。いくつかのアイテムを追加すると、セットは最初のものと2番目のものを覚えていません。
HashSet<T>
は、数学セットをオブジェクトとして表すことができる.NETフレームワークのデータ構造です。この場合、ハッシュコード(GetHashCode
各項目の結果)を使用して、セット要素の同等性を比較します。
セットとリストの違いは、セット内に含まれる同じ要素を1回だけ許可することです。2番目の同じ要素を追加しようとすると、HashSet<T>
単に戻りfalse
ます。実際、O(1)
内部データ構造は単なるハッシュテーブルであるため、要素の検索は非常に高速です(時間)。
どちらを使用するか迷っているList<T>
場合HashSet<T>
は、where is appropiateの使用が最大の間違いではないことに注意してください。ただし、コレクション内に不要な重複アイテムがある場合に問題が発生する可能性があります。さらに、ルックアップ(アイテムの取得)は非常に効率的です-理想的にはO(1)
(完全なバケット化のために)O(n)
時間ではなく-多くのシナリオで非常に重要です。
List<T>
順序付けられた情報のセットを格納するために使用されます。リストの要素の相対的な順序がわかっている場合は、一定の時間でそれらにアクセスできます。ただし、要素がリストのどこにあるかを判別したり、要素がリストに存在するかどうかを確認したりするために、ルックアップ時間は線形です。一方、HashedSet<T>
は格納されたデータの順序を保証せず、その結果、その要素に一定のアクセス時間を提供します。
名前が示すように、HashedSet<T>
は、セットセマンティクスを実装するデータ構造です。データ構造は、集合演算(つまり、Union、Difference、Intersect)を実装するように最適化されています。これは、従来のList実装では効率的に行うことができません。
したがって、使用するデータ型を選択するかどうかは、実際にアプリケーションで何をしようとしているのかに依存します。コレクション内での要素の順序が気にならず、存在を確認または確認するだけの場合は、を使用しますHashSet<T>
。それ以外の場合は、List<T>
または別の適切なデータ構造の使用を検討してください。
要するに、辞書(またはSがTのプロパティである辞書)を使いたくなったら、HashSet(またはHashSet + TにIEquatableを実装し、Sと同等)を検討する必要があります。
基本的な想定シナリオでHashSet<T>
は、LINQが提供するよりも2つのコレクションでより具体的な集合演算が必要な場合に使用する必要があります。LINQのようなメソッドDistinct
、Union
、Intersect
そしてExcept
ほとんどの状況で十分ですが、時にはあなたは、よりきめ細かな操作を必要とする、ともHashSet<T>
用意されています。
UnionWith
IntersectWith
ExceptWith
SymmetricExceptWith
Overlaps
IsSubsetOf
IsProperSubsetOf
IsSupersetOf
IsProperSubsetOf
SetEquals
LINQとの間にもう一つの違いHashSet<T>
「オーバーラップ」の方法は、LINQは常に新しいを返すことでIEnumerable<T>
、及びHashSet<T>
方法は、ソースコレクションを変更します。
SortedSet
データ構造を提供するという事実は、セットのプロパティではない順序についてのあなたの言うことと矛盾するか、または開発チームからの誤解を指摘します。