Utilizziamo i cookie per migliorare la tua esperienza sul sito
CodeWorlds

List Comprehensions - Efektywna eksploracja

Witaj ponownie, @name! Darwin tutaj z kolejnym potężnym narzędziem eksploracyjnym.

W poprzednich lekcjach nauczyłeś/aś się list i słowników. Widziałeś/aś już też zapowiedzi comprehensions - sposobu tworzenia kolekcji w jednej zwięzłej linii. Teraz czas zagłębić się w ten temat!

Comprehensions to jak mapa skarbów - zamiast opisywać krok po kroku jak dotrzeć do celu (tradycyjne pętle), wyrażasz wprost czego szukasz (comprehension). To jedna z najbardziej "pythonowych" cech języka - kod staje się czytelniejszy, krótszy i często szybszy.

Czym są comprehensions?

Comprehension to składnia Pythona pozwalająca tworzyć kolekcje (listy, słowniki, zbiory) w jednej linii, zamiast używać pętli.

1# Tradycyjny sposób (4 linie)
2squares = []
3for x in range(1, 6):
4    squares.append(x ** 2)
5# [1, 4, 9, 16, 25]
6
7# List comprehension (1 linia!)
8squares = [x ** 2 for x in range(1, 6)]
9# [1, 4, 9, 16, 25]

Zalety comprehensions:

  • Krótsze - 1 linia zamiast 3-4
  • Czytelniejsze - wyrażają intencję wprost
  • Szybsze - optymalizowane wewnętrznie przez Python
  • Pythonowe - idiomatyczny styl kodu

List comprehensions - podstawy

Składnia:

[wyrażenie for element in iterable]

1# Przykład 1: Liczby od 0 do 9
2numbers = [x for x in range(10)]
3# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
4
5# Przykład 2: Kwadraty liczb
6squares = [x ** 2 for x in range(1, 11)]
7# [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
8
9# Przykład 3: Konwersja temperatur
10fahrenheit_temps = [32, 68, 104, 212]
11celsius_temps = [(f - 32) * 5/9 for f in fahrenheit_temps]
12# [0.0, 20.0, 40.0, 100.0]
13
14# Przykład 4: Wielkie litery
15animals = ["tygrys", "słoń", "papuga"]
16animals_upper = [animal.upper() for animal in animals]
17# ["TYGRYS", "SŁOŃ", "PAPUGA"]
18
19# Przykład 5: Długości słów
20species = ["Python", "Elephas", "Leo"]
21lengths = [len(s) for s in species]
22# [6, 7, 3]

Safari przykład - Nazwy odkrytych gatunków

1# Mamy listę gatunków (nazwa naukowa)
2discovered = ["python regius", "panthera leo", "loxodonta africana"]
3
4# Chcemy je sformatować: Wielkie litery + zamiana spacji na _
5formatted = [name.upper().replace(" ", "_") for name in discovered]
6# ['PYTHON_REGIUS', 'PANTHERA_LEO', 'LOXODONTA_AFRICANA']
7
8# Lub dodać prefix "SPECIES_"
9prefixed = [f"SPECIES_{name.upper()}" for name in discovered]
10# ['SPECIES_PYTHON REGIUS', 'SPECIES_PANTHERA LEO', 'SPECIES_LOXODONTA AFRICANA']

List comprehensions z warunkami

Składnia:

[wyrażenie for element in iterable if warunek]

1# Przykład 1: Tylko liczby parzyste
2numbers = [x for x in range(1, 11) if x % 2 == 0]
3# [2, 4, 6, 8, 10]
4
5# Przykład 2: Tylko liczby nieparzyste
6odd_numbers = [x for x in range(1, 11) if x % 2 != 0]
7# [1, 3, 5, 7, 9]
8
9# Przykład 3: Tylko dodatnie liczby
10temperatures = [-5, 3, -2, 10, 15, -1, 8]
11positive = [t for t in temperatures if t > 0]
12# [3, 10, 15, 8]
13
14# Przykład 4: Tylko długie słowa (>5 znaków)
15animals = ["Tygrys", "Słoń", "Papuga", "Pyton", "Lew"]
16long_names = [a for a in animals if len(a) > 5]
17# ['Tygrys', 'Papuga']
18
19# Przykład 5: Tylko słowa zaczynające się na 'P'
20p_animals = [a for a in animals if a.startswith('P')]
21# ['Papuga', 'Pyton']

Safari przykład - Filtrowanie odkryć

1# Lista odkrytych gatunków z niebezpiecznością
2species_data = [
3    {"name": "Python regius", "dangerous": False, "size": 1.5},
4    {"name": "Panthera leo", "dangerous": True, "size": 2.5},
5    {"name": "Elephas maximus", "dangerous": False, "size": 3.0},
6    {"name": "Crocodylus niloticus", "dangerous": True, "size": 4.5}
7]
8
9# Tylko niebezpieczne gatunki
10dangerous = [s["name"] for s in species_data if s["dangerous"]]
11# ['Panthera leo', 'Crocodylus niloticus']
12
13# Tylko duże gatunki (>2.5m)
14large = [s["name"] for s in species_data if s["size"] > 2.5]
15# ['Elephas maximus', 'Crocodylus niloticus']
16
17# Tylko bezpieczne i małe (<2m)
18safe_small = [s["name"] for s in species_data
19              if not s["dangerous"] and s["size"] < 2.0]
20# ['Python regius']

If-else w list comprehensions

Składnia:

[wyrażenie_if if warunek else wyrażenie_else for element in iterable]

1# Przykład 1: Parzyste/Nieparzyste etykiety
2numbers = [1, 2, 3, 4, 5]
3labels = ["parzysta" if x % 2 == 0 else "nieparzysta" for x in numbers]
4# ['nieparzysta', 'parzysta', 'nieparzysta', 'parzysta', 'nieparzysta']
5
6# Przykład 2: Klasyfikacja temperatur
7temps = [15, 25, 35, 10, 30]
8classification = ["gorąco" if t > 30 else "normalnie" if t > 20 else "zimno"
9                  for t in temps]
10# ['zimno', 'normalnie', 'gorąco', 'zimno', 'gorąco']
11
12# Przykład 3: Konwersja wartości
13raw_data = [5, 0, 10, -1, 15, 0, 20]
14cleaned = [x if x > 0 else 0 for x in raw_data]
15# [5, 0, 10, 0, 15, 0, 20]

UWAGA: Składnia if-else jest inna niż samego if!

  • Filtrowanie:
    [x for x in lista if warunek]
    - if na końcu
  • Transformacja:
    [x if warunek else y for x in lista]
    - if-else przed for
1# Filtrowanie (pomija elementy)
2result = [x for x in range(10) if x % 2 == 0]
3# [0, 2, 4, 6, 8] - tylko parzyste
4
5# Transformacja (zmienia elementy)
6result = [x if x % 2 == 0 else -x for x in range(10)]
7# [0, -1, 2, -3, 4, -5, 6, -7, 8, -9] - parzyste bez zmian, nieparzyste negowane

Zagnieżdżone list comprehensions

Możesz zagnieżdżać comprehensions dla złożonych transformacji:

1# Przykład 1: Spłaszczanie listy 2D
2matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
3flattened = [num for row in matrix for num in row]
4# [1, 2, 3, 4, 5, 6, 7, 8, 9]
5
6# Przykład 2: Kombinacje
7colors = ["red", "green"]
8sizes = ["S", "M", "L"]
9combinations = [f"{color}_{size}" for color in colors for size in sizes]
10# ['red_S', 'red_M', 'red_L', 'green_S', 'green_M', 'green_L']
11
12# Przykład 3: Mnożenie macierzy (uproszczone)
13matrix_2d = [[1, 2], [3, 4], [5, 6]]
14doubled = [[num * 2 for num in row] for row in matrix_2d]
15# [[2, 4], [6, 8], [10, 12]]

Safari przykład - Kombinacje ekspedycji

1# Zespoły i lokacje
2teams = ["Alfa", "Beta", "Gamma"]
3locations = ["Dżungla", "Sawanna", "Rzeka"]
4
5# Wszystkie możliwe przydziały
6assignments = [f"Zespół {team}{location}"
7               for team in teams for location in locations]
8
9# Wynik:
10# ['Zespół Alfa → Dżungla', 'Zespół Alfa → Sawanna', 'Zespół Alfa → Rzeka',
11#  'Zespół Beta → Dżungla', 'Zespół Beta → Sawanna', 'Zespół Beta → Rzeka',
12#  'Zespół Gamma → Dżungla', 'Zespół Gamma → Sawanna', 'Zespół Gamma → Rzeka']

Dictionary comprehensions

Składnia:

{klucz: wartość for element in iterable}

1# Przykład 1: Kwadraty jako słownik
2squares = {x: x ** 2 for x in range(1, 6)}
3# {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
4
5# Przykład 2: Długości słów
6animals = ["Tygrys", "Słoń", "Papuga"]
7lengths_dict = {animal: len(animal) for animal in animals}
8# {'Tygrys': 6, 'Słoń': 4, 'Papuga': 6}
9
10# Przykład 3: Z dwóch list (zip)
11keys = ["Python", "Leo", "Elephas"]
12values = ["Pyton", "Lew", "Słoń"]
13translation = {k: v for k, v in zip(keys, values)}
14# {'Python': 'Pyton', 'Leo': 'Lew', 'Elephas': 'Słoń'}
15
16# Przykład 4: Odwracanie słownika
17original = {"a": 1, "b": 2, "c": 3}
18reversed_dict = {v: k for k, v in original.items()}
19# {1: 'a', 2: 'b', 3: 'c'}

Dict comprehension z warunkiem

1# Tylko gatunki o nazwie dłuższej niż 5 znaków
2animals = ["Tygrys", "Lew", "Słoń", "Papuga", "Pyton"]
3long_animals = {a: len(a) for a in animals if len(a) > 5}
4# {'Tygrys': 6, 'Papuga': 6}
5
6# Tylko dodatnie wartości
7data = {"a": 5, "b": -3, "c": 10, "d": -1, "e": 7}
8positive_only = {k: v for k, v in data.items() if v > 0}
9# {'a': 5, 'c': 10, 'e': 7}

Safari przykład - Katalog gatunków

1# Lista krotek (nazwa naukowa, nazwa polska, długość)
2species_list = [
3    ("Python regius", "Pyton królewski", 1.5),
4    ("Panthera leo", "Lew", 2.5),
5    ("Elephas maximus", "Słoń azjatycki", 3.0),
6    ("Loxodonta africana", "Słoń afrykański", 3.5)
7]
8
9# Stwórz słownik: nazwa_naukowa → {dane}
10catalog = {
11    name: {"pl": pl_name, "length": length}
12    for name, pl_name, length in species_list
13}
14
15print(catalog["Python regius"])
16# {'pl': 'Pyton królewski', 'length': 1.5}
17
18# Tylko duże gatunki (>2m)
19large_catalog = {
20    name: {"pl": pl_name, "length": length}
21    for name, pl_name, length in species_list
22    if length > 2.0
23}
24# {'Panthera leo': {...}, 'Elephas maximus': {...}, 'Loxodonta africana': {...}}

Set comprehensions

Składnia:

{wyrażenie for element in iterable}

1# Przykład 1: Unikalne długości
2animals = ["Tygrys", "Słoń", "Papuga", "Pyton", "Lew"]
3unique_lengths = {len(a) for a in animals}
4# {3, 4, 5, 6} - zbiór (unordered, unikalne)
5
6# Przykład 2: Pierwsze litery
7first_letters = {a[0] for a in animals}
8# {'T', 'S', 'P', 'L'}
9
10# Przykład 3: Parzyste kwadraty
11even_squares = {x ** 2 for x in range(1, 11) if x % 2 == 0}
12# {4, 16, 36, 64, 100}

Set comprehension automatycznie usuwa duplikaty:

1numbers = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
2unique = {x for x in numbers}
3# {1, 2, 3, 4}
4
5# Można też: set(numbers)
6# Ale set comprehension pozwala na transformacje:
7unique_doubled = {x * 2 for x in numbers}
8# {2, 4, 6, 8}

Generator expressions

Składnia:

(wyrażenie for element in iterable)

Generator expression wygląda jak list comprehension, ale używa

()
zamiast
[]
. Różnica: Generator nie tworzy całej listy w pamięci od razu, tylko generuje elementy "na żądanie".

1# List comprehension - tworzy całą listę
2squares_list = [x ** 2 for x in range(1000000)]  # Zajmuje dużo pamięci!
3
4# Generator expression - generuje po kolei
5squares_gen = (x ** 2 for x in range(1000000))  # Zajmuje mało pamięci!
6
7# Generator możesz iterować tylko raz
8for square in squares_gen:
9    print(square)  # Generuje wartości po kolei

Kiedy używać generatorów:

  • ✅ Gdy przetwarzasz duże zbiory danych
  • ✅ Gdy nie potrzebujesz całej listy od razu
  • ✅ Gdy iterujesz tylko raz
  • ✅ Gdy chcesz oszczędzić pamięć
1# Sumowanie kwadratów (efektywnie z generatorem)
2total = sum(x ** 2 for x in range(1000000))
3
4# Maksimum (efektywnie z generatorem)
5max_val = max(x ** 2 for x in range(1000))
6
7# Filtrowanie z generatorem
8large_numbers = (x for x in range(1000000) if x > 999990)
9for num in large_numbers:
10    print(num)  # Drukuje tylko ostatnie 10 liczb

Safari przykład - Przetwarzanie dużych danych

1# Mamy miliony odkryć w bazie
2def get_all_species():
3    """Symulacja pobierania milionów wpisów"""
4    for i in range(1000000):
5        yield {"id": i, "name": f"Species_{i}", "size": i % 100}
6
7# Źle - tworzy całą listę (pamięciożerne!)
8# large_species = [s["name"] for s in get_all_species() if s["size"] > 90]
9
10# Dobrze - używa generatora (oszczędne!)
11large_species = (s["name"] for s in get_all_species() if s["size"] > 90)
12
13# Możemy iterować bez ładowania wszystkiego do pamięci
14for species in large_species:
15    print(species)

Comprehensions vs tradycyjne pętle

Kiedy używać comprehensions?

Użyj comprehension gdy:

  • ✅ Transformujesz prostą kolekcję
  • ✅ Filtrujesz elementy po prostym warunku
  • ✅ Kod mieści się w 1 linii (max 80-100 znaków)
  • ✅ Logika jest prosta i czytelna

Użyj tradycyjnej pętli gdy:

  • ❌ Logika jest złożona (wiele if/else)
  • ❌ Potrzebujesz wielu operacji na każdym elemencie
  • ❌ Kod staje się nieczytelny
  • ❌ Potrzebujesz obsługi wyjątków (try/except)

Porównanie

1# ✅ Dobre zastosowanie comprehension
2squares = [x ** 2 for x in range(10)]
3even = [x for x in range(20) if x % 2 == 0]
4names = [s.upper() for s in species]
5
6# ❌ Źle - za skomplikowane dla comprehension
7result = [
8    process_complex_logic(x, y, z)
9    if check_condition_1(x) and check_condition_2(y)
10    else alternative_processing(x)
11    if check_condition_3(z)
12    else default_value
13    for x, y, z in complicated_data
14    if validate(x) and validate(y) and validate(z)
15]  # NIE RÓB TAK!
16
17# ✅ Lepiej - tradycyjna pętla
18result = []
19for x, y, z in complicated_data:
20    if not (validate(x) and validate(y) and validate(z)):
21        continue
22
23    if check_condition_1(x) and check_condition_2(y):
24        result.append(process_complex_logic(x, y, z))
25    elif check_condition_3(z):
26        result.append(alternative_processing(x))
27    else:
28        result.append(default_value)

Wydajność comprehensions

Comprehensions są zazwyczaj szybsze niż tradycyjne pętle!

1import time
2
3# Tradycyjna pętla
4start = time.time()
5result = []
6for x in range(1000000):
7    result.append(x ** 2)
8time_loop = time.time() - start
9
10# List comprehension
11start = time.time()
12result = [x ** 2 for x in range(1000000)]
13time_comp = time.time() - start
14
15print(f"Pętla: {time_loop:.4f}s")
16print(f"Comprehension: {time_comp:.4f}s")
17print(f"Comprehension jest {time_loop/time_comp:.2f}x szybsze!")
18
19# Typowe wyniki:
20# Pętla: 0.1234s
21# Comprehension: 0.0987s
22# Comprehension jest 1.25x szybsze!

Dlaczego comprehensions są szybsze?

  • Python optymalizuje je wewnętrznie
  • Mniej wywołań funkcji (np. append())
  • Interpreter "wie" co robisz i może zoptymalizować

Praktyczny przykład - Analiza ekspedycji

1# Dane ekspedycji (dzień, dystans km, odkryte gatunki, temperatura °C)
2expedition_log = [
3    (1, 15, 3, 32),
4    (2, 12, 5, 31),
5    (3, 8, 2, 35),
6    (4, 20, 7, 33),
7    (5, 10, 4, 30),
8    (6, 18, 6, 34),
9    (7, 14, 3, 32)
10]
11
12# 1. Całkowity dystans
13total_distance = sum(day[1] for day in expedition_log)
14print(f"Całkowity dystans: {total_distance} km")  # 97 km
15
16# 2. Średnia temperatura
17avg_temp = sum(day[3] for day in expedition_log) / len(expedition_log)
18print(f"Średnia temperatura: {avg_temp:.1f}°C")  # 32.4°C
19
20# 3. Dni z dużą liczbą odkryć (>4)
21productive_days = [day[0] for day in expedition_log if day[2] > 4]
22print(f"Produktywne dni: {productive_days}")  # [2, 4, 6]
23
24# 4. Słownik: dzień → dane
25daily_stats = {
26    day: {"distance": dist, "species": spec, "temp": temp}
27    for day, dist, spec, temp in expedition_log
28}
29print(daily_stats[1])  # {'distance': 15, 'species': 3, 'temp': 32}
30
31# 5. Klasyfikacja dni
32day_types = {
33    day: "produktywny" if spec > 5 else "normalny" if spec > 3 else "słaby"
34    for day, dist, spec, temp in expedition_log
35}
36print(day_types)
37# {1: 'słaby', 2: 'normalny', 3: 'słaby', 4: 'produktywny',
38#  5: 'normalny', 6: 'produktywny', 7: 'słaby'}
39
40# 6. Tylko gorące dni (>33°C)
41hot_days = [(day, temp) for day, dist, spec, temp in expedition_log if temp > 33]
42print(f"Gorące dni: {hot_days}")  # [(3, 35), (6, 34)]

Nested dict/list comprehensions - zaawansowane

1# Przykład: Macierz odległości między lokacjami
2locations = ["Obóz", "Rzeka", "Wodospad", "Szczyt"]
3
4# Stwórz macierz odległości (losowe wartości)
5import random
6distance_matrix = {
7    loc1: {
8        loc2: random.randint(5, 50) if loc1 != loc2 else 0
9        for loc2 in locations
10    }
11    for loc1 in locations
12}
13
14print(distance_matrix["Obóz"])
15# {'Obóz': 0, 'Rzeka': 23, 'Wodospad': 41, 'Szczyt': 37}
16
17# Znajdź wszystkie pary lokacji z odległością <20km
18close_pairs = [
19    f"{loc1}{loc2}"
20    for loc1, distances in distance_matrix.items()
21    for loc2, dist in distances.items()
22    if 0 < dist < 20
23]
24print(close_pairs)

Zadanie praktyczne

Stwórz "Species Analysis System":

  1. Lista 20 losowych gatunków z danymi (nazwa, rozmiar 0.1-5.0m, niebezpieczny T/F)
  2. Użyj comprehensions do:
    • Słownik: nazwa → dane
    • Lista tylko niebezpiecznych gatunków
    • Słownik: kategoria rozmiaru → lista gatunków
    • Średni rozmiar dla każdej kategorii
    • Top 5 największych gatunków

Podsumowanie

W tej lekcji nauczyłeś/aś się:

  • ✅ Czym są comprehensions i dlaczego są potężne
  • ✅ List comprehensions (podstawowe i z warunkami)
  • ✅ Dictionary comprehensions
  • ✅ Set comprehensions
  • ✅ Generator expressions (oszczędność pamięci)
  • ✅ Zagnieżdżone comprehensions
  • ✅ Kiedy używać comprehensions vs pętle
  • ✅ Wydajność comprehensions

Checkpoint

Przed przejściem dalej:

  • [ ] Rozumiesz składnię list comprehension
  • [ ] Potrafisz używać warunków (if) w comprehensions
  • [ ] Rozumiesz różnicę między
    if
    a
    if-else
    w comprehension
  • [ ] Potrafisz tworzyć dict comprehensions
  • [ ] Znasz różnicę między listą a generatorem
  • [ ] Wiesz kiedy używać comprehension, a kiedy pętlę

Pythonowa zasada: "Proste jest lepsze niż skomplikowane" - jeśli comprehension robi kod nieczytelnym, użyj tradycyjnej pętli!

W następnej lekcji Darwin wprowadzi Cię w złożoność algorytmów - jak mierzyć tempo eksploracji! ⏱️🚀

Vai a CodeWorlds