C#でHashSetを使用する方法

HashSetは、順序付けされていない一意の要素の最適化されたコレクションであり、高速なルックアップと高性能のセット操作を提供します。HashSetクラスは.NET3.5で最初に導入され、System.Collection.Generic名前空間の一部です。この記事では、C#でHashSetを操作する方法について説明します。

この記事で提供されているコード例を使用するには、システムにVisual Studio2019がインストールされている必要があります。まだコピーをお持ちでない場合は、こちらからVisual Studio2019をダウンロードできます。

VisualStudioで.NETCoreコンソールアプリケーションプロジェクトを作成します

まず、VisualStudioで.NETCoreコンソールアプリケーションプロジェクトを作成しましょう。Visual Studio 2019がシステムにインストールされていると仮定して、以下に概説する手順に従って、VisualStudioで新しい.NETCoreコンソールアプリケーションプロジェクトを作成します。

  1. Visual StudioIDEを起動します。
  2. 「新しいプロジェクトの作成」をクリックします。
  3. 「新規プロジェクトの作成」ウィンドウで、表示されたテンプレートのリストから「コンソールアプリ(.NETCore)」を選択します。
  4. [次へ]をクリックします。
  5. 次に表示される[新しいプロジェクトの構成]ウィンドウで、新しいプロジェクトの名前と場所を指定します。
  6. [作成]をクリックします。

これにより、Visual Studio2019で新しい.NETCoreコンソールアプリケーションプロジェクトが作成されます。このプロジェクトを使用して、この記事の後続のセクションでHashSetを操作します。

HashSetとは何ですか?

HashSet — System.Collections.Generic名前空間に関連するHashSetクラスで表される—は、一意の要素の高性能で順序付けられていないコレクションです。したがって、HashSetはソートされず、重複する要素は含まれません。HashSetはインデックスもサポートしていません—列挙子のみを使用できます。HashSetは通常、一意のデータのセットを含む高性能操作に使用されます。

HashSetクラスは、以下に示すようにいくつかのインターフェースを実装します。

パブリッククラスHashSet:System.Collections.Generic.ICollection、

System.Collections.Generic.IEnumerable、

System.Collections.Generic.IReadOnlyCollection、

System.Collections.Generic.ISet、

System.Runtime.Serialization.IDeserializationCallback、

System.Runtime.Serialization.ISerializable

HashSetには一意の要素しか含まれていないため、その内部構造は検索を高速化するために最適化されています。HashSetに単一のnull値を格納できることに注意してください。したがって、HashSetは、一意の要素を含むコレクションが必要で、コレクション内の要素をすばやく検索できる場合に適しています。

C#でHashSet内のアイテムを検索する

HashSet内のアイテムを検索するには、以下のコードスニペットに示すようにContainsメソッドを使用できます。

static void Main(string [] args)

        {{

            HashSet hashSet = new HashSet();

            hashSet.Add( "A");

            hashSet.Add( "B");

            hashSet.Add( "C");

            hashSet.Add( "D");

            if(hashSet.Contains( "D"))

                Console.WriteLine( "必要な要素が利用可能です。");

            そうしないと

                Console.WriteLine( "必要な要素が利用できません。");

            Console.ReadKey();

        }

HashSet要素は常に一意です

重複する要素をHashSetに挿入しようとすると、それは単に無視されますが、実行時例外はスローされません。次のコードスニペットはこれを示しています。

static void Main(string [] args)

{{

   HashSet hashSet = new HashSet();

   hashSet.Add( "A");

   hashSet.Add( "B");

   hashSet.Add( "C");

   hashSet.Add( "D");

   hashSet.Add( "D");

   Console.WriteLine( "要素の数は次のとおりです:{0}"、hashSet.Count);

   Console.ReadKey();

}

プログラムを実行すると、出力は図1のようになります。

次に、重複する要素がどのように排除されるかを示す次のコードスニペットについて考えてみます。

string []都市=新しいstring [] {

                「デリー」、

                「コルカタ」、

                "ニューヨーク"、

                「ロンドン」、

                "東京"、

                「ワシントン」、

                "東京"

            };

            HashSet hashSet = new HashSet(cities);

            foreach(hashSetのvar city)

            {{

                Console.WriteLine(city);

            }

上記のプログラムを実行すると、重複する都市名が削除されます。

C#のHashSetから要素を削除します

HashSetからアイテムを削除するには、Removeメソッドを呼び出す必要があります。Removeメソッドの構文を以下に示します。

public bool Remove(T item);

アイテムがコレクションで見つかった場合、RemoveメソッドはHashSetから要素を削除し、成功した場合はtrueを返し、それ以外の場合はfalseを返します。

以下に示すコードスニペットは、Removeメソッドを使用してHashSetからアイテムを削除する方法を示しています。

string item = "D";

if(hashSet.Contains(item))

{{

   hashSet.Remove(item);

}

HashSetからすべてのアイテムを削除するには、Clearメソッドを使用できます。

C#でHashSetセット操作メソッドを使用する

HashSetには、IntersectWith、UnionWith、IsProperSubsetOf、ExceptWith、SymmetricExceptWithなどのセット操作のための重要なメソッドがいくつかあります。

IsProperSubsetOf

IsProperSubsetOfメソッドは、HashSetインスタンスがコレクションの適切なサブセットであるかどうかを判別するために使用されます。これは、以下のコードスニペットに示されています。

HashSet setA = new HashSet(){"A"、 "B"、 "C"、 "D"};

HashSet setB = new HashSet(){"A"、 "B"、 "C"、 "X"};

HashSet setC = new HashSet(){"A"、 "B"、 "C"、 "D"、 "E"};

if(setA.IsProperSubsetOf(setC))

   Console.WriteLine( "setCにはsetAのすべての要素が含まれています。");

if(!setA.IsProperSubsetOf(setB))

   Console.WriteLine( "setBにはsetAのすべての要素が含まれているわけではありません。");

上記のプログラムを実行すると、コンソールウィンドウに次の出力が表示されます。

UnionWith

以下に示すコードスニペットに示すように、UnionWithメソッドはセットの追加に使用されます。

HashSet setA = new HashSet(){"A"、 "B"、 "C"、 "D"、 "E"};

HashSet setB = new HashSet(){"A"、 "B"、 "C"、 "X"、 "Y"};

setA.UnionWith(setB);

foreach(setAのstring str)

{{

   Console.WriteLine(str);

}

上記のコードを実行すると、setBの要素がsetAにコピーされます。したがって、setAには、「A」、「B」、「C」、「D」、「E」、「X」、および「Y」が含まれるようになります。 

IntersectWith 

IntersectWithメソッドは、2つのHashSetの共通部分を表すために使用されます。これを理解するための例を次に示します。

HashSet setA = new HashSet(){"A"、 "B"、 "C"、 "D"、 "E"};

HashSet setB = new HashSet(){"A"、 "X"、 "C"、 "Y"};

setA.IntersectWith(setB);

foreach(setAの文字列str)

{{

    Console.WriteLine(str);

}

上記のプログラムを実行すると、2つのHashSetに共通の要素のみがコンソールウィンドウに表示されます。出力は次のようになります。 

ExceptWith

ExceptWithメソッドは、数学的な集合の減算を表し、O(n)演算です。2つのHashSetsetAとsetBがあり、次のステートメントを指定するとします。

setA.ExceptWith(setB);

これにより、setBに存在しないsetAの要素が返されます。別の例でこれを理解しましょう。以下に示すコードスニペットについて考えてみます。

HashSet setA = new HashSet(){"A"、 "B"、 "C"、 "D"、 "E"};

HashSet setB = new HashSet(){"A"、 "X"、 "C"、 "Y"};

setA.ExceptWith(setB);

foreach(setAの文字列str)

{{

   Console.WriteLine(str);

}

上記のプログラムを実行すると、図5に示すように、要素「B」、「D」、および「E」がコンソールウィンドウに出力されます。

SymmetricExceptWith 

SymmetricExceptWithメソッドは、2つのHashSetの一意の要素、つまり両方のHashSetに共通ではない要素のみを含むようにHashSetを変更するために使用されます。これを説明する次のコードスニペットについて考えてみます。

HashSet setA = new HashSet(){"A"、 "B"、 "C"、 "D"、 "E"};

HashSet setB = new HashSet(){"A"、 "X"、 "C"、 "Y"};

setA.SymmetricExceptWith(setB);

foreach(setAの文字列str)

{{

  Console.WriteLine(str);

}

上記のコードを実行すると、setAとsetBの一意の要素(つまり、setAには存在するがsetBには存在しない要素、およびsetBには存在するがsetAには存在しない要素)のみがコンソールウィンドウに表示されます。図6に示すように。

配列内の要素にアクセスするための平均的な複雑さはO(n)ですが、nは配列内の要素の数を表しますが、HashSet内の特定の要素にアクセスするための複雑さはO(1)です。これにより、HashSetは、高速検索やセット操作の実行に適しています。アイテムのコレクションを特定の順序で保存し、重複を含める場合は、リストを使用できます。 

C#でさらに多くのことを行う方法:

  • C#で名前付きパラメーターとオプションのパラメーターを使用する方法
  • BenchmarkDotNetを使用してC#コードをベンチマークする方法
  • C#で流暢なインターフェイスとメソッドチェーンを使用する方法
  • C#で静的メソッドを単体テストする方法
  • C#で神オブジェクトをリファクタリングする方法
  • C#でValueTaskを使用する方法
  • Cで不変性を使用する方法
  • C#でconst、readonly、staticを使用する方法
  • C#でデータ注釈を使用する方法
  • C#8でGUIDを操作する方法
  • C#で抽象クラスとインターフェイスを使用する場合
  • C#でAutoMapperを操作する方法
  • C#でラムダ式を使用する方法
  • C#でAction、Func、およびPredicateデリゲートを操作する方法
  • C#でデリゲートを操作する方法
  • C#で簡単なロガーを実装する方法
  • C#で属性を操作する方法
  • C#でlog4netを操作する方法
  • C#でリポジトリデザインパターンを実装する方法
  • C#でリフレクションを操作する方法
  • C#でfilesystemwatcherを操作する方法
  • C#でレイジー初期化を実行する方法
  • C#でMSMQを操作する方法
  • C#で拡張メソッドを操作する方法
  • C#でラムダ式を使用する方法
  • C#でvolatileキーワードを使用する場合
  • C#でyieldキーワードを使用する方法
  • C#でポリモーフィズムを実装する方法
  • C#で独自のタスクスケジューラを構築する方法
  • C#でRabbitMQを操作する方法
  • C#でタプルを操作する方法
  • C#での仮想メソッドと抽象メソッドの調査
  • C#でDapperORMを使用する方法
  • C#でフライウェイトデザインパターンを使用する方法