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 elementAdd 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 3Podzbió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); // trueRó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 sameBrak 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
- Lista w praktyce
- Wyszukiwanie w Dictionary
- HashSet i unikatowość
- Wybór kolekcji