0Pricing
C# Academy · レッスン

HashSetと一意性

重複しない値を管理します。

「HashSetと一意性」はCoddyKit上の無料C# Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはC# Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 C# Academyコースには全4レッスンが含まれています。

HashSet とは

HashSet<T> は重複のない一意な値のコレクションを格納します。すでに存在する値を追加しても、何も行われません。

Dictionary と同様にハッシュテーブルを基盤としているため、メンバーシップの確認は平均 O(1) です。挿入順序は保持しません。

using System.Collections.Generic;

var seen = new HashSet<int>();
seen.Add(1);
seen.Add(1); // ignored, still one element

Add は bool を返す

Add は、値が新規の場合は true を、すでに存在する場合は false を返します。

この戻り値を使うと、別途 Contains で確認しなくても、1 回の操作で重複を検出できます。

using System;
using System.Collections.Generic;

class Program {
    static void Main() {
        var set = new HashSet<string>();
        Console.WriteLine(set.Add("a")); // True
        Console.WriteLine(set.Add("a")); // False
    }
}

高速なメンバーシップ確認

HashSet の Contains は平均 O(1) ですが、List では O(n) です。

「これはすでに確認したか」を繰り返し調べる場合は、set が適しています。コレクションが大きくなるほど、速度の差は大幅に広がります。

using System;
using System.Collections.Generic;

class Program {
    static void Main() {
        var ids = new HashSet<int> { 10, 20, 30 };
        Console.WriteLine(ids.Contains(20)); // True
        Console.WriteLine(ids.Contains(99)); // False
    }
}

リストから重複を削除する

よくある処理として、リストから値の重複を取り除き、一意な値だけを残すことがあります。リストから HashSet を構築すれば、これを O(n) で実行できます。

結果の set には各値が 1 回ずつ含まれます。リストに戻す必要がある場合は、new List<int>(set) のようにラップしてください。

using System;
using System.Collections.Generic;

class Program {
    static void Main() {
        var nums = new List<int> { 1, 2, 2, 3, 3, 3 };
        var unique = new HashSet<int>(nums);
        Console.WriteLine(unique.Count); // 3
    }
}

和集合

UnionWith は、別のコレクションのすべての要素を重複を飛ばしながら追加します。結果には両方のコレクションの要素がすべて含まれます。

この操作では set 自体が変更されます。自分で各項目に対してループしながら Add を呼び出すより、はるかに簡潔です。

using System;
using System.Collections.Generic;

class Program {
    static void Main() {
        var a = new HashSet<int> { 1, 2, 3 };
        a.UnionWith(new[] { 3, 4, 5 });
        Console.WriteLine(a.Count); // 5
    }
}

積集合

IntersectWith は、他のコレクションにも存在する要素だけを残し、それ以外を削除します。

2 つの記事で共有されているタグや、2 つのグループの両方に属するユーザーなど、共通する項目を見つけるときに使用します。

using System;
using System.Collections.Generic;

class Program {
    static void Main() {
        var a = new HashSet<int> { 1, 2, 3, 4 };
        a.IntersectWith(new[] { 2, 4, 6 });
        Console.WriteLine(string.Join(",", a)); // 2,4
    }
}

差集合

ExceptWith は、他のコレクションに存在する要素を set から削除し、set にしか存在しない要素を残します。

これは集合の差の演算、つまり「A に含まれるが B には含まれない項目」です。変更点や、これから処理する項目を計算するのに適しています。

var a = new HashSet<int> { 1, 2, 3, 4 };
a.ExceptWith(new[] { 2, 4 });
// a now contains 1 and 3

部分集合と上位集合

IsSubsetOf と IsSupersetOf は、set 同士の包含関係を調べ、bool を返します。

Overlaps は共通する要素があるかを確認し、SetEquals は順序に関係なく 2 つの set がまったく同じ要素を含むかを確認します。

var a = new HashSet<int> { 1, 2 };
var b = new HashSet<int> { 1, 2, 3 };
bool sub = a.IsSubsetOf(b);   // true
bool ov = a.Overlaps(b);      // true

要素の等価性

一意性は、Dictionary のキーと同じく、要素の型の GetHashCode と Equals に依存します。

カスタム型では両方をオーバーライドするか、record を使用してください。そうしないと、論理的に等しい 2 つのオブジェクトが別々のものとして扱われ、両方が set に追加されます。

var names = new HashSet<string>(
    System.StringComparer.OrdinalIgnoreCase);
names.Add("Sam");
bool dup = !names.Add("SAM"); // true: treated as same

インデックスと順序はない

HashSet にはインデックスによるアクセスがなく、set[0] のようには書けません。foreach で列挙することだけができます。

列挙の順序は保証されません。一意性と並べ替え済みの順序の両方が必要な場合は、要素を順序付きで保持する SortedSet<T> を使用してください。ただし、操作の計算量は O(log n) になります。

using System;
using System.Collections.Generic;

class Program {
    static void Main() {
        var s = new SortedSet<int> { 3, 1, 2 };
        Console.WriteLine(string.Join(",", s)); // 1,2,3
    }
}

確認済み項目を追跡する

よく使われるパターンに、ストリームをフィルタリングして各値を 1 回だけ出現させる方法があります。set に追加し、Add が true を返した場合だけ処理します。

これは増え続けるリストを確認するよりも簡潔で高速です。O(n²) の走査を O(n) にできます。

using System;
using System.Collections.Generic;

class Program {
    static void Main() {
        var seen = new HashSet<int>();
        foreach (int x in new[] { 1, 1, 2, 3, 2 })
            if (seen.Add(x)) Console.Write(x + " ");
        // prints 1 2 3
    }
}

確認問題

HashSet が保証することと、その検索コストを思い出してください。

まとめ

HashSet<T> は一意な値を格納し、追加、削除、メンバーシップの確認を平均 O(1) で行えます。ただし、順序とインデックスはありません。

重複排除、「これはすでに確認したか」という高速な確認、そして UnionWith、IntersectWith、ExceptWith による集合演算で特に力を発揮します。カスタム要素型には適切な等価性が必要です。

よくある質問

「HashSetと一意性」レッスンは無料ですか?

はい。「HashSetと一意性」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、C# Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 C# Academyコースには全4レッスンが含まれています。

「HashSetと一意性」で何を学びますか?

重複しない値を管理します。 ブラウザで直接実行するハンズオンコードでC# Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

C# Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのC# Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。

「HashSetと一意性」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このC# Academyレッスンでコードを書いて実行できますか?

はい。すべてのC# Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. Listを実践する
  2. Dictionaryの検索
  3. HashSetと一意性
  4. コレクションを選ぶ
← C# Academyに戻る