Niemutowalne krotki, zbiory bez duplikatów, operacje teoriomnogościowe.
Krotka to niemutowalna, uporządkowana sekwencja elementów. Wygląda jak lista, ale po utworzeniu nie można jej modyfikować — nie można dodawać, usuwać ani zmieniać elementów.
(elem1, elem2, ...)a, b = 1, 2(5,) — bez niego to po prostu 5# Tworzenie krotek
punkt = (3, 7)
kolor = (255, 128, 0)
dane = ("Kasia", 17, "3A")
pusta = ()
jedna = (42,) # przecinek obowiązkowy!
# Bez nawiasów — też krotka
wspolrz = 10, 20
print(type(wspolrz)) # <class 'tuple'>
# Indeksowanie — jak lista
print(punkt[0]) # 3
print(kolor[-1]) # 0
print(dane[1:]) # (17, '3A')
# Rozpakowywanie
x, y = punkt
print(x, y) # 3 7
imie, wiek, klasa = dane
print(imie, wiek) # Kasia 17
# _ dla ignorowanych wartości
imie, _, klasa = dane
print(imie, klasa) # Kasia 3A
Krotka ma tylko dwie metody (bo nie można jej modyfikować). Operacje odczytu działają tak samo jak dla list.
| Operacja/Metoda | Działanie | Przykład |
|---|---|---|
len(t) | długość krotki | len((1,2,3)) → 3 |
t.count(x) | liczba wystąpień x | (1,2,1).count(1) → 2 |
t.index(x) | indeks pierwszego x | (3,5,7).index(5) → 1 |
x in t | czy x jest w krotce | 3 in (1,3,5) → True |
t1 + t2 | łączenie krotek | (1,2)+(3,4) → (1,2,3,4) |
t * n | powielenie | (0,)*3 → (0,0,0) |
min(t), max(t) | min i max | jak dla list |
sorted(t) | zwraca posortowaną listę | zwraca list, nie tuple |
t[0] = 99 → TypeError. Nie można też dodać ani usunąć elementu. Można jednak tworzyć nowe krotki z istniejących: nowa = t + (99,).
oceny = (4, 5, 3, 5, 4, 2, 5)
print(len(oceny)) # 7
print(oceny.count(5)) # 3
print(oceny.index(3)) # 2
print(min(oceny)) # 2
print(max(oceny)) # 5
print(sum(oceny)) # 28
# Łączenie
a = (1, 2, 3)
b = (4, 5, 6)
c = a + b
print(c) # (1, 2, 3, 4, 5, 6)
# Konwersja lista ↔ krotka
lista = [1, 2, 3]
krotka = tuple(lista)
print(krotka) # (1, 2, 3)
z_krotki = list(krotka)
print(z_krotki) # [1, 2, 3]
# Krotki jako klucze słownika
pozycje = {(0,0): "start", (5,3): "cel"}
print(pozycje[(0,0)]) # start
# Swap bez zmiennej pomocniczej
a, b = 10, 20
a, b = b, a
print(a, b) # 20 10
Zbiór to nieuporządkowana kolekcja unikalnych elementów. Automatycznie eliminuje duplikaty. Idealny gdy ważna jest przynależność, nie kolejność.
{elem1, elem2, ...}set() — nie {} bo to pusty słownik!in) jest bardzo szybkie — O(1)s = {} tworzy pusty słownik, nie zbiór! Pusty zbiór to s = set(). To częsty błąd — uważaj na egzaminie.
# Tworzenie zbiorów
owoce = {"jabłko", "gruszka", "śliwka"}
liczby = {1, 2, 3, 4, 5}
pusty = set()
# Duplikaty są automatycznie usuwane
z_dup = {1, 2, 2, 3, 3, 3, 4}
print(z_dup) # {1, 2, 3, 4}
# Z listy — usunięcie duplikatów
lista = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3]
unikalne = set(lista)
print(unikalne) # {1, 2, 3, 4, 5, 6, 9}
# Konwersja z powrotem na listę
czysta = sorted(list(unikalne))
print(czysta) # [1, 2, 3, 4, 5, 6, 9]
# Sprawdzanie przynależności — szybkie!
print("jabłko" in owoce) # True
print("mango" in owoce) # False
print(7 in liczby) # False
| Metoda | Działanie |
|---|---|
add(x) | dodaje element x |
remove(x) | usuwa x — błąd gdy brak |
discard(x) | usuwa x — brak błędu gdy nie ma |
pop() | usuwa i zwraca losowy element |
clear() | usuwa wszystkie elementy |
copy() | płytka kopia zbioru |
update(s2) | dodaje wszystkie elementy z s2 |
len(s) | liczba elementów |
remove(x) rzuca KeyError gdy x nie istnieje. discard(x) po prostu nic nie robi. Na egzaminie gdy nie masz pewności czy element jest w zbiorze — używaj discard().
s = {1, 2, 3, 4, 5}
# Dodawanie
s.add(6)
s.add(3) # 3 już jest — nic się nie zmienia
print(s) # {1, 2, 3, 4, 5, 6}
# Usuwanie
s.remove(6)
print(s) # {1, 2, 3, 4, 5}
s.discard(99) # nie ma 99 — brak błędu
s.discard(5)
print(s) # {1, 2, 3, 4}
# update — dodaj z innego zbioru lub listy
s.update([10, 11, 12])
print(s) # {1, 2, 3, 4, 10, 11, 12}
# Iterowanie — kolejność nieokreślona
for elem in s:
print(elem, end=" ")
# Rozmiar
print(len(s)) # 7
Zbiory w Pythonie obsługują klasyczne operacje z teorii zbiorów. Można je wykonywać zarówno operatorami jak i metodami.
| Operacja | Operator | Metoda | Znaczenie |
|---|---|---|---|
| Suma | A | B | A.union(B) | elementy w A lub B |
| Przecięcie | A & B | A.intersection(B) | elementy w A i B |
| Różnica | A - B | A.difference(B) | elementy w A, nie w B |
| Różnica sym. | A ^ B | A.symmetric_difference(B) | w A lub B, ale nie w obu |
| Podzbiór | A <= B | A.issubset(B) | czy A ⊆ B |
| Nadzbiór | A >= B | A.issuperset(B) | czy A ⊇ B |
| Rozłączność | — | A.isdisjoint(B) | czy A ∩ B = ∅ |
A = {1, 2, 3, 4, 5}
B = {4, 5, 6, 7, 8}
# Suma — wszystko z obu
print(A | B) # {1, 2, 3, 4, 5, 6, 7, 8}
# Przecięcie — wspólne
print(A & B) # {4, 5}
# Różnica — w A, nie w B
print(A - B) # {1, 2, 3}
print(B - A) # {6, 7, 8}
# Różnica symetryczna
print(A ^ B) # {1, 2, 3, 6, 7, 8}
# Relacje między zbiorami
C = {1, 2}
print(C <= A) # True — C jest podzbiorem A
print(A >= C) # True — A jest nadzbiorem C
print(A.isdisjoint({10, 11})) # True — brak wspólnych
# Praktyczne zastosowanie
klasa_3A = {"Kasia", "Marek", "Zofia", "Piotr"}
klasa_3B = {"Marek", "Ola", "Tomek", "Zofia"}
w_obu = klasa_3A & klasa_3B
print(f"W obu klasach: {w_obu}") # Marek, Zofia
tylko_3A = klasa_3A - klasa_3B
print(f"Tylko w 3A: {tylko_3A}")
frozenset to niemutowalny zbiór — jak krotka dla listy. Może być kluczem słownika lub elementem innego zbioru.
| Cecha | list | tuple | set | frozenset |
|---|---|---|---|---|
| Mutowalny | ✓ | ✗ | ✓ | ✗ |
| Kolejność | ✓ | ✓ | ✗ | ✗ |
| Duplikaty | ✓ | ✓ | ✗ | ✗ |
| Indeksowanie | ✓ | ✓ | ✗ | ✗ |
| Klucz słownika | ✗ | ✓ | ✗ | ✓ |
| Szybkie in | O(n) | O(n) | O(1) | O(1) |
# frozenset — niemutowalny zbiór
fs = frozenset([1, 2, 3, 4])
print(fs) # frozenset({1, 2, 3, 4})
# Może być kluczem słownika
grupy = {
frozenset({"Kasia", "Marek"}): "Projekt A",
frozenset({"Zofia", "Piotr"}): "Projekt B"
}
# Szybkie sprawdzanie przynależności — set vs list
import time
duza_lista = list(range(1_000_000))
duzy_zbior = set(duza_lista)
# set jest wielokrotnie szybszy dla 'in'
print(999_999 in duzy_zbior) # True — O(1)
print(999_999 in duza_lista) # True — O(n), wolniej
# Usuwanie duplikatów z zachowaniem kolejności
def unikalne_z_kolejnoscia(lst):
widziane = set()
wynik = []
for x in lst:
if x not in widziane:
widziane.add(x)
wynik.append(x)
return wynik
lst = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3]
print(unikalne_z_kolejnoscia(lst))
# [3, 1, 4, 5, 9, 2, 6]
Wczytaj zainteresowania dwóch osób (oddzielone przecinkami). Wypisz: zainteresowania wspólne, unikalne dla pierwszej osoby, unikalne dla drugiej, oraz wszystkie łącznie bez powtórzeń.
wejscie1 = input("Zainteresowania osoby 1 (po przecinku): ")
wejscie2 = input("Zainteresowania osoby 2 (po przecinku): ")
zbior1 = set(z.strip().lower() for z in wejscie1.split(","))
zbior2 = set(z.strip().lower() for z in wejscie2.split(","))
wspolne = zbior1 & zbior2
tylko1 = zbior1 - zbior2
tylko2 = zbior2 - zbior1
wszystkie = zbior1 | zbior2
print(f"Wspólne: {wspolne or 'brak'}")
print(f"Tylko osoba 1: {tylko1 or 'brak'}")
print(f"Tylko osoba 2: {tylko2 or 'brak'}")
print(f"Wszystkie: {wszystkie}")
set(z.strip().lower() for z in wejscie.split(",")) — dzielimy po przecinku, każdy element czyścimy ze spacji i zamieniamy na małe litery, a set eliminuje duplikaty.
& daje elementy w obu zbiorach, - daje elementy tylko w lewym, | daje wszystkie elementy z obu. Czytelne i krótkie.
wspolne or 'brak' wypisze "brak" gdy zbiór jest pusty — zamiast brzydkiego set().
Napisz funkcję statystyki(liczby) przyjmującą listę liczb i zwracającą krotkę: (min, max, suma, średnia). Użyj jej wynik w rozpakowaniu.
def statystyki(liczby):
if not liczby:
return None
mini = min(liczby)
maxi = max(liczby)
suma = sum(liczby)
srednia = suma / len(liczby)
return mini, maxi, suma, srednia
dane = [5, 3, 8, 1, 9, 2, 7, 4, 6]
mini, maxi, suma, srednia = statystyki(dane)
print(f"Min: {mini}")
print(f"Max: {maxi}")
print(f"Suma: {suma}")
print(f"Średnia: {srednia:.2f}")
# Można też używać jako krotki
wynik = statystyki(dane)
print(f"Zakres: {wynik[0]}–{wynik[1]}")
mini, maxi, suma, srednia = statystyki(dane) — lewa strona musi mieć dokładnie tyle zmiennych ile elementów w krotce. Każda zmienna dostaje odpowiednią wartość.
if not liczby: return None — pusta lista jest falsy. Bez tego min([]) rzuciłby ValueError.
Wczytaj n liczb całkowitych. Używając zbiorów wypisz: które liczby się powtarzają, ile jest unikalnych wartości oraz czy wszystkie liczby są różne.
n = int(input("Ile liczb? "))
liczby = []
for i in range(n):
liczby.append(int(input(f"Liczba {i+1}: ")))
zbior = set(liczby)
duplikaty = set()
for l in liczby:
if liczby.count(l) > 1:
duplikaty.add(l)
print(f"Wczytano: {liczby}")
print(f"Unikalne: {sorted(zbior)}")
print(f"Ile unikalnych: {len(zbior)}")
if duplikaty:
print(f"Powtarzające: {sorted(duplikaty)}")
else:
print("Wszystkie liczby są różne!")
len(zbior) to liczba unikalnych wartości.
sorted(zbior) zwraca posortowaną listę unikalnych elementów. Czytelniejszy wynik.
Ćwicz rozpakowywanie krotek i operacje na zbiorach — to często pojawia się na egzaminie w nieoczywistych miejscach.
Zamiana bez zmiennej
Wczytaj trzy liczby a, b, c. Wykonaj rotację: a→b, b→c, c→a — używając rozpakowywania krotki w jednej linii.
a, b, c = c, a, bUnikalne litery
Wczytaj dwa słowa. Wypisz litery które są tylko w pierwszym, tylko w drugim i w obu. Ignoruj wielkość liter i spacje.
set(slowo.lower()), operatory &, -, |Funkcja minmax
Napisz funkcję minmax(lista) zwracającą krotkę (minimum, maksimum) bez użycia wbudowanych min() i max(). Przetestuj na kilku listach.
Sito z użyciem zbioru
Zaimplementuj Sito Eratostenesa używając zbioru zamiast listy. Zacznij od zbioru wszystkich liczb od 2 do n i odejmuj wielokrotności.
zbior -= {i*k for k in range(2, n//i+1)}Krotki w słowniku
Stwórz słownik gdzie kluczem jest krotka (x, y) a wartością odległość punktu od początku układu. Wypełnij dla punktów (0–3, 0–3). Wypisz posortowane po odległości.
(x**2 + y**2)**0.5, sorted(d.items(), key=lambda x: x[1])Pokrycie zbiorami
Masz uniwersum liczb 1–20 i listę podzbiorów. Znajdź minimalną liczbę podzbiorów potrzebną do pokrycia całego uniwersum (greedy — zawsze wybieraj podzbiór pokrywający najwięcej niepokrytych elementów).
while niepokryte, wybierz podzbiór z max len(p & niepokryte)