Map i Set — słowniki oraz zbiory
Policz głosy i usuń duplikaty uczestników. Map łączy klucz z wartością, a Set pilnuje unikalności elementów.
Po tej lekcji potrafisz
- Użyjesz set, get, has, delete, clear i size kolekcji Map.
- Zastosujesz add, has i iterację po Set.
- Wyjaśnisz równość kluczy obiektowych i kolejność iteracji.
Głosowanie na grę wieczoru
Dla każdego tytułu chcemy pamiętać liczbę głosów. Szukanie tytułu w kilku tablicach szybko robi się niewygodne. Map daje jasne powiązanie nazwa → licznik. Set przyda się do listy unikalnych uczestników.
Małe kroki, konkretne efekty
Map pamięta pary klucz–wartość
Map<string, number> ma tekstowe klucze i liczbowe wartości. set dodaje lub zastępuje wartość pod kluczem. get zwraca wartość albo undefined; size to liczba par.
const punkty = new Map<string, number>();
punkty.set("Ala", 10);
punkty.set("Ala", 20);
console.log(punkty.get("Ala"), punkty.size);
console.log(punkty.has("Neo"), punkty.get("Neo") ?? 0);
console.log(punkty.delete("Ala"), punkty.size);
punkty.clear();
20 1
false 0
true 0
delete informuje, czy klucz istniał. clear usuwa wszystkie wpisy. Nie ustawiaj wartości przez punkty[„Ala”] — to inny mechanizm właściwości obiektów.
Set trzyma unikalne wartości
Powtórne add tej samej wartości nie zwiększa zbioru. Set zachowuje kolejność pierwszego dodania pozostających elementów. Ma size, a nie length.
const nicki = new Set(["Ala", "Neo", "Ala"]);
nicki.add("Ola");
console.log([...nicki].join(", "), nicki.size);
console.log(nicki.has("Neo"));
nicki.delete("Neo");
console.log([...nicki].join(", "));
nicki.clear();
console.log(nicki.size);
Ala, Neo, Ola 3
true
Ala, Ola
0
Spread zamienia iterowalny zbiór na tablicę. „ala” i „Ala” to różne wartości; ujednolicenie wielkości liter jest osobną decyzją.
Wyniki głosowania
Każdy wpis w tablicy to głos. Na tym etapie zakładamy, że uprawnienia głosujących sprawdzono wcześniej. Nasz program jedynie zlicza tytuły.
const glosy = ["Kosmos", "Wyścigi", "Kosmos", "Puzzle", "Wyścigi", "Kosmos"];
const licznik = new Map<string, number>();
for (const tytul of glosy) {
licznik.set(tytul, (licznik.get(tytul) ?? 0) + 1);
}
for (const [tytul, liczba] of licznik) {
console.log(tytul + ": " + liczba);
}
console.log("Gier: " + licznik.size);
Kosmos: 3
Wyścigi: 2
Puzzle: 1
Gier: 3
Jak program dochodzi do wyniku
- Brak poprzedniego licznika zastępujemy zerem.
- set nadpisuje licznik danego tytułu nową liczbą.
- Iteracja Map daje pary [klucz, wartość], które rozpakowujemy destrukturyzacją.
- Kolejność wynika z pierwszego dodania kluczy, a nie z liczby głosów.
Zanim przejdziesz dalej
Czy set(„Kosmos”, 99) utworzy drugi wpis Kosmos?
Sprawdź swoje rozumowanie
Nie. Zastąpi wartość istniejącego klucza i nie zwiększy size.
Zmień kod i zobacz, co się stanie
Obiekty są porównywane przez tożsamość
Dwa osobno utworzone obiekty z tymi samymi polami nie są tym samym kluczem. Zbiór takich obiektów też nie usuwa duplikatów według ich treści.
const a = { id: 1 };
const b = { id: 1 };
const zbior = new Set([a, b, a]);
console.log(zbior.size);
const mapa = new Map<object, string>([[a, "Pierwszy"]]);
console.log(mapa.get(b) ?? "Inny obiekt");
console.log([...mapa.values()].join(","));
2
Inny obiekt
Pierwszy
Jeśli unikalność ma zależeć od id, przechowuj id jako klucz. Map i Set uznają NaN za równe NaN, a 0 i -0 za ten sam klucz — to nieco inne reguły niż samo ===.
Gdy wynik zaskakuje
| Pomyłka | Co się dzieje i jak to poprawić |
|---|---|
| length zamiast size | Map i Set udostępniają liczbę wpisów przez size. |
| get bez obsługi braku | Brak klucza daje undefined. |
| Set obiektów jako usuwanie duplikatów po id | Zbiór porównuje tożsamość obiektów. Wybierz Set identyfikatorów. |
Teraz Twoja kolej
Rozwiązanie jest jedną z możliwości. Zanim je odkryjesz, uruchom własną wersję dla podanych danych i przynajmniej jednego przypadku brzegowego.
Usuń powtórzenia z [„ts”, „gry”, „ts”, „kod”] i zachowaj kolejność pierwszego pojawienia.
Mała podpowiedź
Set i spread.
Przykładowe rozwiązanie z wyjaśnieniem
console.log([...new Set(["ts", "gry", "ts", "kod"])].join(","));
ts,gry,kod
Nie jest potrzebne sortowanie.
Map ma przechowywać „naklejka” → 5 i „kubek” → 20. Wypisz cenę kubka, usuń naklejkę, sprawdź size.
Mała podpowiedź
set, get, delete.
Przykładowe rozwiązanie z wyjaśnieniem
const ceny = new Map<string, number>([["naklejka", 5], ["kubek", 20]]);
console.log(ceny.get("kubek"));
ceny.delete("naklejka");
console.log(ceny.size);
20
1
Klucz daje bezpośredni dostęp do przypisanej wartości.
Wyznacz wspólne nicki list [„Ala”, „Neo”] i [„Neo”, „Ola”]. Wynik ma nie mieć duplikatów.
Mała podpowiedź
Dwa zbiory i filter z has.
Przykładowe rozwiązanie z wyjaśnieniem
const a = new Set(["Ala", "Neo"]);
const b = new Set(["Neo", "Ola"]);
console.log([...a].filter(nick => b.has(nick)).join(","));
Neo
Wybieramy tylko elementy pierwszego zbioru obecne w drugim.
Dla zgłoszeń o id 1, 2, 1 zaakceptuj tylko pierwsze wystąpienie każdego id. Wypisz „Ala, Neo”, pomijając trzecie zgłoszenie „Max”.
Mała podpowiedź
Set<number> pamięta już widziane identyfikatory.
Przykładowe rozwiązanie z wyjaśnieniem
const zgloszenia = [{ id: 1, nick: "Ala" }, { id: 2, nick: "Neo" }, { id: 1, nick: "Max" }];
const widziane = new Set<number>();
const wynik = zgloszenia.filter(z => {
if (widziane.has(z.id)) { return false; }
widziane.add(z.id); return true;
});
console.log(wynik.map(z => z.nick).join(", "));
Ala, Neo
To kontrolowany efekt uboczny callbacku; zbiór należy do tej operacji filtrowania.
Co zabierasz do następnej lekcji
- Map łączy klucz z wartością; Set przechowuje unikalne elementy.
- Kolekcje pamiętają kolejność dodawania, ale nie sortują.
- Klucze obiektowe są porównywane przez tożsamość.