← Strona główna

06 — Listy i tablice

Tworzenie, indeksowanie, metody list, list comprehension, listy zagnieżdżone.

Struktury i pętle

1. Czym jest lista i jak ją tworzyć?

Lista to uporządkowana, mutowalna kolekcja elementów. Może przechowywać elementy różnych typów. Jest jedną z najważniejszych struktur danych w Pythonie.

  • Tworzona w nawiasach kwadratowych: [elem1, elem2, ...]
  • Może być pusta: []
  • Elementy mogą być różnych typów — liczby, teksty, inne listy
  • Mutowalna — można dodawać, usuwać i zmieniać elementy
  • Zachowuje kolejność elementów
  • Dopuszcza duplikaty
Lista vs tablica W Pythonie lista pełni rolę tablicy z innych języków. Nie ma stałego rozmiaru — rośnie dynamicznie. Do tablic numerycznych (np. w obliczeniach) używa się biblioteki numpy, ale na egzaminie INF.04 wystarczą listy.
Przykład — tworzenie list
# Listy różnych typów
liczby   = [1, 2, 3, 4, 5]
imiona   = ["Kasia", "Marek", "Zofia"]
mieszana = [1, "tekst", 3.14, True]
pusta    = []

# Lista z range()
od_zera  = list(range(10))
print(od_zera)    # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

# Lista przez powielenie
zera     = [0] * 5
print(zera)       # [0, 0, 0, 0, 0]

# Lista z tekstu
litery   = list("Python")
print(litery)     # ['P', 'y', 't', 'h', 'o', 'n']

# Zagnieżdżona — macierz 3x3
macierz  = [[1, 2, 3],
            [4, 5, 6],
            [7, 8, 9]]
print(macierz[1][2])  # 6

2. Indeksowanie i wycinki (slice)

Elementy listy są numerowane od 0. Można też używać indeksów ujemnych — liczonych od końca.

ZapisZnaczenie
lista[0]pierwszy element
lista[-1]ostatni element
lista[-2]przedostatni element
lista[2:5]elementy od indeksu 2 do 4
lista[:3]pierwsze 3 elementy
lista[2:]od indeksu 2 do końca
lista[::2]co drugi element
lista[::-1]odwrócona lista
Pułapka — IndexError Odwołanie do nieistniejącego indeksu powoduje IndexError. Dla listy 5-elementowej poprawne indeksy to 0–4 (lub -5 do -1).
Przykład — indeksowanie i slice
oceny = [3, 4, 5, 2, 4, 5, 3]
#        0  1  2  3  4  5  6
#       -7 -6 -5 -4 -3 -2 -1

print(oceny[0])      # 3 — pierwszy
print(oceny[-1])     # 3 — ostatni
print(oceny[2])      # 5 — trzeci
print(oceny[-2])     # 5 — przedostatni

# Wycinki
print(oceny[1:4])    # [4, 5, 2]
print(oceny[:3])     # [3, 4, 5]
print(oceny[4:])     # [4, 5, 3]
print(oceny[::2])    # [3, 5, 4, 3] — co drugi
print(oceny[::-1])   # [3, 5, 4, 2, 5, 4, 3] — odwrócona

# Zmiana elementu przez indeks
oceny[3] = 6
print(oceny)         # [3, 4, 5, 6, 4, 5, 3]

3. Metody list

MetodaDziałanieZwraca
append(x)dodaje x na koniecNone
insert(i, x)wstawia x na pozycję iNone
extend(lista)dodaje wszystkie elementy listyNone
remove(x)usuwa pierwsze wystąpienie xNone
pop()usuwa i zwraca ostatni elementelement
pop(i)usuwa i zwraca element z indeksu ielement
index(x)indeks pierwszego wystąpienia xint
count(x)ile razy x występuje na liścieint
sort()sortuje listę w miejscuNone
reverse()odwraca listę w miejscuNone
clear()usuwa wszystkie elementyNone
copy()zwraca płytką kopię listylista
sort() vs sorted() lista.sort() — modyfikuje oryginał, zwraca None.
sorted(lista) — zwraca nową listę, oryginał bez zmian.
Obie przyjmują reverse=True i key=funkcja.
Przykład — metody list
lista = [3, 1, 4, 1, 5]

# Dodawanie
lista.append(9)
print(lista)         # [3, 1, 4, 1, 5, 9]

lista.insert(2, 99)
print(lista)         # [3, 1, 99, 4, 1, 5, 9]

lista.extend([10, 11])
print(lista)         # [3, 1, 99, 4, 1, 5, 9, 10, 11]

# Usuwanie
lista.remove(99)     # usuwa pierwsze 99
print(lista)         # [3, 1, 4, 1, 5, 9, 10, 11]

ostatni = lista.pop()
print(ostatni)       # 11
print(lista)         # [3, 1, 4, 1, 5, 9, 10]

# Informacje
print(lista.index(4))   # 2 — pozycja czwórki
print(lista.count(1))   # 2 — ile jedynek

# Sortowanie
lista.sort()
print(lista)         # [1, 1, 3, 4, 5, 9, 10]

lista.sort(reverse=True)
print(lista)         # [10, 9, 5, 4, 3, 1, 1]

4. Operacje na listach — in, len, del, +, *

OperacjaZnaczeniePrzykład
len(lista)długość listylen([1,2,3]) → 3
x in listaczy x jest na liście5 in [1,5,3] → True
x not in listaczy x nie jest na liście7 not in [1,5,3] → True
lista1 + lista2łączenie list[1,2]+[3,4] → [1,2,3,4]
lista * npowielenie listy[0]*3 → [0,0,0]
del lista[i]usuwa element o indeksie idel lista[2]
del lista[a:b]usuwa wycinekdel lista[1:3]
Kopiowanie listy b = a — to nie jest kopia! Obie zmienne wskazują na tę samą listę. Żeby skopiować: b = a.copy(), b = a[:] lub b = list(a).
Przykład — operacje na listach
a = [1, 2, 3, 4, 5]

# Sprawdzanie przynależności
print(3 in a)        # True
print(9 in a)        # False
print(9 not in a)    # True

# Łączenie i powielanie
b = [6, 7, 8]
c = a + b
print(c)             # [1, 2, 3, 4, 5, 6, 7, 8]
print([0] * 4)       # [0, 0, 0, 0]

# Usuwanie przez del
d = [10, 20, 30, 40, 50]
del d[2]
print(d)             # [10, 20, 40, 50]
del d[1:3]
print(d)             # [10, 50]

# Pułapka z kopiowaniem
oryg  = [1, 2, 3]
alias = oryg          # to samo miejsce w pamięci!
alias.append(99)
print(oryg)           # [1, 2, 3, 99] — zmienione!

kopia = oryg.copy()   # prawdziwa kopia
kopia.append(0)
print(oryg)           # [1, 2, 3, 99] — bez zmian

5. List comprehension — zaawansowane

List comprehension to elegancki sposób tworzenia list. Omawialiśmy podstawy w kafelku 04 — tutaj rozszerzamy o bardziej złożone przypadki.

  • Z warunkiem: [x for x in lista if warunek]
  • Z transformacją i warunkiem: [f(x) for x in lista if warunek]
  • Zagnieżdżone: [x for wiersz in macierz for x in wiersz]
  • Z if-else: [a if warunek else b for x in lista]
Kolejność w zagnieżdżonym [x for wiersz in macierz for x in wiersz] — kolejność pętli taka sama jak przy zagnieżdżeniu: najpierw zewnętrzna (wiersz), potem wewnętrzna (x).
Przykład — list comprehension zaawansowane
# Filtrowanie z transformacją
liczby = range(1, 21)
nieparzyste_kwadraty = [x**2 for x in liczby if x % 2 != 0]
print(nieparzyste_kwadraty)
# [1, 9, 25, 49, 81, 121, 169, 225, 289, 361]

# if-else wewnątrz
wyniki = [x if x >= 0 else 0 for x in [-3, 5, -1, 8, -2]]
print(wyniki)      # [0, 5, 0, 8, 0]

# Spłaszczenie macierzy
macierz = [[1,2,3],[4,5,6],[7,8,9]]
plaska  = [x for wiersz in macierz for x in wiersz]
print(plaska)      # [1, 2, 3, 4, 5, 6, 7, 8, 9]

# Pary (x, y) gdzie x != y
pary = [(x, y) for x in range(1,4)
               for y in range(1,4)
               if x != y]
print(pary)
# [(1,2),(1,3),(2,1),(2,3),(3,1),(3,2)]

6. Listy zagnieżdżone — macierze 2D

Lista list to odpowiednik tablicy dwuwymiarowej. Każdy wiersz to osobna lista.

  • Dostęp: macierz[wiersz][kolumna]
  • Tworzenie pustej macierzy n×m: przez list comprehension
  • Iterowanie: dwie pętle zagnieżdżone
  • Uwaga na kopiowanie — [[0]*3]*3 tworzy 3 referencje do tej samej listy!
Bezpieczne tworzenie macierzy [[0 for _ in range(m)] for _ in range(n)] — tworzy n wierszy, każdy to osobna lista m zer. Metoda [[0]*m]*n jest niebezpieczna — wszystkie wiersze to ten sam obiekt.
Przykład — macierze 2D
# Macierz 3x3
m = [[1, 2, 3],
     [4, 5, 6],
     [7, 8, 9]]

print(m[0])         # [1, 2, 3] — pierwszy wiersz
print(m[1][2])      # 6 — wiersz 1, kolumna 2

# Iterowanie
for wiersz in m:
    for elem in wiersz:
        print(elem, end=" ")
    print()

# Bezpieczna pusta macierz 4x3
pusta = [[0 for _ in range(3)] for _ in range(4)]
pusta[1][2] = 9
print(pusta)
# [[0,0,0],[0,0,9],[0,0,0],[0,0,0]]

# Suma wszystkich elementów
suma = sum(m[i][j] for i in range(3) for j in range(3))
print(suma)         # 45

# Transponowanie macierzy
t = [[m[j][i] for j in range(3)] for i in range(3)]
print(t)  # [[1,4,7],[2,5,8],[3,6,9]]

Zadania przykładowe z omówieniem

Zadanie 1 Usuwanie duplikatów z zachowaniem kolejności łatwe

Masz listę z powtarzającymi się elementami. Utwórz nową listę bez duplikatów, zachowując kolejność pierwszych wystąpień. Wypisz obie listy i liczbę usuniętych duplikatów.

Rozwiązanie
lista = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]

bez_duplikatow = []
for elem in lista:
    if elem not in bez_duplikatow:
        bez_duplikatow.append(elem)

usunieto = len(lista) - len(bez_duplikatow)

print(f"Oryginalna:      {lista}")
print(f"Bez duplikatów:  {bez_duplikatow}")
print(f"Usunięto:        {usunieto} duplikatów")
Omówienie krok po kroku
  1. Pusta lista docelowa
    Zaczynamy od pustej listy bez_duplikatow. Będziemy do niej dodawać tylko te elementy, których jeszcze nie ma.
  2. Warunek not in
    if elem not in bez_duplikatow sprawdza czy element już trafił do nowej listy. Jeśli nie — dodajemy go. Jeśli tak — pomijamy.
  3. Zachowanie kolejności
    Iterujemy po oryginalnej liście od lewej — pierwszy napotkany element trafia do wyniku. Kolejne wystąpienia są ignorowane. Kolejność jest zachowana.
  4. Liczba duplikatów
    Różnica długości list to liczba pominiętych (duplikatowych) elementów.
Zadanie 2 Oceny uczniów — statystyki średnie

Wczytaj od użytkownika n ocen (liczba n też jest wczytywana). Oblicz i wypisz: średnią, medianę, modę (najczęstszą ocenę), liczbę ocen powyżej średniej.

Rozwiązanie
n = int(input("Ile ocen? "))
oceny = []
for i in range(n):
    o = int(input(f"Ocena {i+1}: "))
    oceny.append(o)

# Średnia
srednia = sum(oceny) / len(oceny)

# Mediana
posortowane = sorted(oceny)
srodek = len(posortowane) // 2
if len(posortowane) % 2 == 0:
    mediana = (posortowane[srodek-1] + posortowane[srodek]) / 2
else:
    mediana = posortowane[srodek]

# Moda — najczęstsza ocena
moda = max(set(oceny), key=oceny.count)

# Powyżej średniej
pow_sredniej = len([o for o in oceny if o > srednia])

print(f"Średnia:          {srednia:.2f}")
print(f"Mediana:          {mediana}")
print(f"Moda:             {moda}")
print(f"Powyżej średniej: {pow_sredniej}")
Omówienie krok po kroku
  1. Mediana — środkowy element
    Sortujemy listę, bierzemy środkowy element. Dla parzystej liczby elementów mediana to średnia dwóch środkowych. srodek = n // 2 daje indeks.
  2. Moda przez max() z key
    set(oceny) daje unikalne wartości. max(..., key=oceny.count) wybiera tę, która najczęściej pojawia się na liście. Eleganckie jednoliniowe rozwiązanie.
  3. List comprehension do zliczania
    [o for o in oceny if o > srednia] tworzy listę ocen powyżej średniej. len() zlicza ile ich jest. Można też użyć pętli z licznikiem.
Zadanie 3 Rotacja listy średnie

Napisz funkcję rotuj(lista, k) która przesuwa elementy listy o k pozycji w prawo. Np. dla [1,2,3,4,5] i k=2 wynik to [4,5,1,2,3]. Rozwiąż to bez tworzenia nowej listy (w miejscu) używając wycinków.

Rozwiązanie
def rotuj(lista, k):
    n = len(lista)
    k = k % n          # obsługa k > n
    lista[:] = lista[-k:] + lista[:-k]

# Test
a = [1, 2, 3, 4, 5]
rotuj(a, 2)
print(a)   # [4, 5, 1, 2, 3]

b = [1, 2, 3, 4, 5]
rotuj(b, 7)   # 7 % 5 = 2, to samo co k=2
print(b)   # [4, 5, 1, 2, 3]

c = ["a", "b", "c", "d"]
rotuj(c, 1)
print(c)   # ['d', 'a', 'b', 'c']
Omówienie krok po kroku
  1. k % n — normalizacja przesunięcia
    Jeśli k=7 a lista ma 5 elementów — to samo co k=2. Modulo eliminuje nadmiarowe obroty i obsługuje k większe od długości listy.
  2. lista[-k:] — ostatnie k elementów
    lista[-2:] dla k=2 daje [4, 5] — te trafią na początek po rotacji.
  3. lista[:-k] — wszystko poza ostatnimi k
    lista[:-2] daje [1, 2, 3] — te trafią na koniec.
  4. lista[:] = ... — modyfikacja w miejscu
    lista[:] = nowa_wartość zastępuje zawartość tej samej listy. Gdybyśmy napisali lista = ... — stworzylibyśmy nową zmienną lokalną, oryginał by się nie zmienił.

Zadania do samodzielnego rozwiązania

Korzystaj z metod list, list comprehension i operacji na wycinkach. Nie używaj gotowych funkcji tam gdzie zadanie prosi o samodzielną implementację.

1★☆☆

Odwrócenie listy

Odwróć listę bez użycia reverse() ani [::-1] — napisz własną funkcję używając pętli i zamiany elementów miejscami.

Wskazówka: zamień lista[i] z lista[n-1-i], iteruj do połowy
2★☆☆

Filtrowanie listy

Masz listę liczb. Używając list comprehension utwórz trzy nowe listy: liczby ujemne, zero i dodatnie. Wypisz każdą z nich.

Wskazówka: trzy osobne list comprehension z warunkiem if
3★★☆

Sortowanie bąbelkowe

Zaimplementuj sortowanie bąbelkowe na liście liczb — dwie zagnieżdżone pętle, zamiana sąsiednich elementów. Nie używaj sort() ani sorted().

Wskazówka: jeśli lista[j] > lista[j+1] — zamień je miejscami
4★★☆

Wspólne elementy

Masz dwie listy liczb. Znajdź ich część wspólną (elementy obecne w obu) bez duplikatów. Nie używaj zbiorów — użyj list i pętli.

Wskazówka: if elem in lista2 and elem not in wynik
5★★☆

Macierz — suma wierszy i kolumn

Dla macierzy 4×4 (wpisanej ręcznie w kod) oblicz i wypisz sumę każdego wiersza i każdej kolumny oraz sumę przekątnej głównej.

Wskazówka: sum(macierz[i]) dla wiersza, macierz[i][j] dla kolumny
6★★★

Scalanie posortowanych list

Masz dwie posortowane listy. Scal je w jedną posortowaną listę bez użycia sort() — porównuj elementy z obu list i buduj wynik element po elemencie.

Wskazówka: dwa wskaźniki i, j — porównuj a[i] z b[j], mniejszy dodaj do wyniku