0Pricing
C# Academy · Lekcja

HashSet i unikatowość

Będzie Pan/Pani śledzić różne wartości.

HashSet i unikatowość to bezpłatna lekcja C# Academy na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej C# Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs C# Academy zawiera 4 lekcji w sumie.

Czym jest HashSet?

HashSet<T> przechowuje kolekcję unikatowych wartości bez duplikatów. Dodanie wartości, która już istnieje, po prostu nic nie robi.

Podobnie jak słownik, korzysta z tablicy haszującej, dlatego sprawdzanie przynależności ma średnią złożoność O(1). Nie zachowuje kolejności wstawiania elementów.

using System.Collections.Generic;

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

Add zwraca wartość bool

Add zwraca true, jeśli wartość była nowa, oraz false, jeśli już istniała.

Zwracana wartość pozwala wykryć duplikaty w jednym kroku, bez osobnego sprawdzania za pomocą Contains.

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
    }
}

Szybkie sprawdzanie przynależności

Contains w kolekcji HashSet ma średnią złożoność O(1), w porównaniu z O(n) w przypadku List.

Jeśli wielokrotnie sprawdzają Państwo, czy dana wartość już się pojawiła, właściwym narzędziem jest zbiór. Wraz ze wzrostem kolekcji różnica szybkości staje się bardzo wyraźna.

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
    }
}

Usuwanie duplikatów z listy

Częste zadanie polega na pobraniu listy i pozostawieniu w niej wyłącznie różnych wartości. Utworzenie HashSet na podstawie listy wykonuje to w czasie O(n).

Wynikowy zbiór zawiera każdą wartość tylko raz. Jeśli potrzebna jest ponownie lista, należy ją opakować: 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
    }
}

Suma zbiorów

UnionWith dodaje każdy element z innej kolekcji, pomijając duplikaty. Wynik zawiera wszystkie elementy z obu kolekcji.

Ta operacja modyfikuje zbiór bezpośrednio. Jest znacznie czytelniejsza niż samodzielne wykonywanie pętli i wywoływanie Add dla każdego elementu.

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
    }
}

Część wspólna

IntersectWith pozostawia tylko elementy, które występują również w innej kolekcji, usuwając pozostałe.

Należy użyć tej operacji do znajdowania wspólnych elementów, takich jak tagi współdzielone przez dwa artykuły lub użytkownicy należący do obu grup.

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
    }
}

Różnica zbiorów

ExceptWith usuwa ze zbioru każdy element znaleziony w innej kolekcji, pozostawiając elementy unikatowe dla tego zbioru.

Jest to operacja różnicy zbiorów: „elementy należące do A, ale nie do B”. Świetnie nadaje się do obliczania zmian lub elementów pozostałych do przetworzenia.

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

Podzbiór i nadzbiór

IsSubsetOf i IsSupersetOf sprawdzają relacje zawierania między zbiorami, zwracając wartość typu bool.

Overlaps sprawdza, czy zbiory mają jakikolwiek wspólny element, a SetEquals — czy dwa zbiory zawierają dokładnie te same elementy, niezależnie od ich kolejności.

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

Równość elementów

Unikatowość zależy od metod GetHashCode i Equals typu elementu, dokładnie tak jak w przypadku kluczy słownika.

W przypadku niestandardowych typów należy przesłonić obie metody lub użyć typu record. W przeciwnym razie dwa logicznie równe obiekty zostaną uznane za różne i oba trafią do zbioru.

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

Brak indeksowania i kolejności

HashSet nie zapewnia dostępu za pomocą indeksu — nie można napisać set[0]. Można po nim jedynie iterować za pomocą foreach.

Kolejność iteracji nie jest gwarantowana. Jeśli potrzebują Państwo zarówno unikatowości, jak i sortowania, należy użyć SortedSet<T>, który utrzymuje elementy w kolejności kosztem operacji o złożoności 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
    }
}

Śledzenie odwiedzonych elementów

Częstym wzorcem jest filtrowanie strumienia tak, aby każda wartość pojawiła się tylko raz. Należy dodać ją do zbioru i wykonać działanie tylko wtedy, gdy Add zwróci true.

Jest to czytelniejsze i szybsze niż sprawdzanie rosnącej listy, ponieważ zmienia skanowanie o złożoności O(n kwadrat) na 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
    }
}

Szybkie sprawdzenie

Należy przypomnieć sobie, jakie ograniczenia nakłada HashSet i jaki jest koszt wyszukiwania.

Podsumowanie

HashSet<T> przechowuje unikatowe wartości, zapewniając średnią złożoność O(1) dodawania, usuwania i sprawdzania przynależności, ale nie oferuje kolejności ani indeksowania.

Doskonale nadaje się do usuwania duplikatów, szybkiego sprawdzania „czy już to widziałem” oraz operacji na zbiorach za pomocą UnionWith, IntersectWith i ExceptWith. Niestandardowe typy elementów wymagają prawidłowej implementacji równości.

Często zadawane pytania

Czy lekcja „HashSet i unikatowość” jest bezpłatna?

Tak — pełny tekst „HashSet i unikatowość” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu C# Academy, przejdź na CoddyKit PRO. Kurs C# Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „HashSet i unikatowość”?

Będzie Pan/Pani śledzić różne wartości. Ćwiczysz C# Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć C# Academy?

Nie wymagamy żadnego doświadczenia. C# Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.

Ile czasu zajmuje lekcja „HashSet i unikatowość”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji C# Academy?

Tak. Każda lekcja C# Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Lista w praktyce
  2. Wyszukiwanie w Dictionary
  3. HashSet i unikatowość
  4. Wybór kolekcji
← Powrót do C# Academy