Zbiór to nieuporządkowany worek unikalnych elementów
Listom i krotkom zależy na kolejności, zbiorom nie. Listy pozwalają gromadzić duplikaty, a zbiory po cichu je pomijają. Zbiór to właściwa struktura danych, gdy masz dwie konkretne potrzeby:
- Chcesz unikalnych elementów, i tyle.
- Chcesz szybko sprawdzać przynależność.
Zapisujesz go w nawiasach klamrowych:
Powtórzone "red" i "green" w drugim zbiorze po prostu znikają. To nie błąd, tylko cały sens zbioru.
Tworzenie zbiorów
Dwa sposoby, których będziesz faktycznie używać:
Ten ostatni punkt każdego kiedyś zaskoczy: {} tworzy pusty słownik, a nie pusty zbiór. Niejednoznaczność składni musiała przypaść jednemu z nich i wygrały słowniki.
Dodawanie i usuwanie
Kluczowa różnica to remove kontra discard: remove wymaga, żeby element istniał; discard jest to obojętne. Wybierz w zależności od tego, czy brak elementu powinien być błędem.
Szybkie sprawdzanie przynależności
Tu zbiory naprawdę zasługują na swoje miejsce. x in some_set działa w stałym czasie, niezależnie od wielkości zbioru. x in some_list musi przejść po liście, co robi się wolne, gdy lista jest duża.
Praktyczna zasada: za każdym razem, gdy piszesz if x in some_list w pętli, a lista ma więcej niż kilkadziesiąt elementów, najpierw zamień listę na zbiór.
Matematyka zbiorów
Tu zbiory robią się naprawdę ciekawe. Możesz łączyć je operatorami, które odpowiadają matematycznym operacjom na zbiorach:
Każdy operator ma też wersję w postaci metody (.union(), .intersection(), .difference(), .symmetric_difference()). Operatory są zwięźlejsze; metody przyjmują dowolny obiekt iterowalny, a nie tylko inny zbiór.
Usuwanie duplikatów z listy
Jedno z najczęstszych zastosowań zbiorów, nawet poza "logiką zbiorów":
Jedna linia i duplikatów nie ma. Warto zauważyć jedno: kolejność nie jest zachowana. Jeśli potrzebujesz unikalności i pierwotnej kolejności, użyj zamiast tego dict.fromkeys():
We współczesnym Pythonie słowniki zachowują kolejność wstawiania, a dict.fromkeys buduje słownik, w którym kluczami są elementy obiektu iterowalnego. W praktyce to uporządkowany zbiór.
Podzbiory i nadzbiory
Sprawdzanie, czy jeden zbiór zawiera się w innym:
Przydaje się to na przykład przy sprawdzaniu uprawnień ("czy ten użytkownik ma wszystkie wymagane role?").
Co może trafić do zbioru
Tylko elementy hashowalne. To termin techniczny, a w praktyce oznacza:
- Rzeczy niemodyfikowalne są hashowalne: liczby, napisy, krotki z elementów hashowalnych, frozenset.
- Rzeczy modyfikowalne nie są: listy, słowniki i inne zbiory nie mogą być elementami zbioru.
Jeśli potrzebujesz zbioru zbiorów, użyj frozenset, czyli niemodyfikowalnej wersji zbioru.
Iteracja jest nieuporządkowana
Pętla po zbiorze zwraca elementy bez gwarantowanej kolejności:
Uruchom to kilka razy, a zobaczysz, że kolejność się zmienia. Jeśli kolejność ma znaczenie, zbiór nie jest właściwą strukturą: posortuj zawartość, gdy jej potrzebujesz, albo użyj listy.
Kiedy nie używać zbioru
Jeśli spełniony jest którykolwiek z tych warunków, lista albo słownik prawdopodobnie pasują lepiej:
- Zależy ci na kolejności.
- Musisz przechowywać duplikaty.
- Każdy element ma powiązane dane (użyj słownika z elementem jako kluczem).
Co dalej
Zbiory zajmują się unikalnością i przynależnością. Słowniki, omówione na następnej stronie, obsługują szerszy wzorzec "znajdź wartość po kluczu", co czyni je prawdopodobnie najbardziej przydatną strukturą danych w Pythonie poza listą.
Najczęściej zadawane pytania
Czym jest zbiór (set) w Pythonie?
Zbiór to nieuporządkowana kolekcja unikalnych elementów. Zbiory zapisuje się w nawiasach klamrowych bez par klucz-wartość: colors = {'red', 'green', 'blue'}. Dodanie tej samej wartości drugi raz nic nie zmienia: duplikaty są po cichu pomijane.
Kiedy używać zbioru zamiast listy?
Używaj zbioru, gdy zależy ci na unikalności albo gdy będziesz często sprawdzać przynależność (x in collection). Zbiory automatycznie usuwają duplikaty i sprawdzają przynależność w stałym czasie, co przy dużych kolekcjach daje ogromne przyspieszenie w porównaniu z listami.
Jak utworzyć pusty zbiór w Pythonie?
Użyj set(), a nie {}: puste nawiasy klamrowe tworzą pusty słownik, a nie pusty zbiór. Gdy masz już zbiór, możesz dodawać elementy przez .add(value).