Przejdź do głównej treści
eLearner.app
Moduł 8 · Lekcja 3 z 431/36 w kursie~12 min
Lekcje modułu (3/4)

collections: Counter i defaultdict

Moduł collections dodaje wyspecjalizowane typy danych rozszerzające wbudowane kolekcje. Trzy najczęściej używane to: Counter, defaultdict oraz namedtuple.

Counter: zliczanie częstotliwości

Python
from collections import Counter

parole = ["mela", "pera", "mela", "kiwi", "mela", "pera"]
c = Counter(parole)
# Counter({'mela': 3, 'pera': 2, 'kiwi': 1})

c["mela"]            # 3
c["banana"]          # 0   (default for missing keys, NO KeyError)
c.most_common(2)     # [('mela', 3), ('pera', 2)]

Działa również na ciągach znaków (zlicza znaki):

Python
Counter("ciao mondo")
# Counter({'o': 2, 'c': 1, 'i': 1, 'a': 1, ' ': 1, 'm': 1, 'n': 1, 'd': 1})

Obsługuje operacje na licznikach podobne do operacji na zbiorach (+, -, &, |) — niezwykle przydatne przy agregowaniu liczników z różnych źródeł.

defaultdict: słownik z automatyczną wartością domyślną

Słownik, który przy próbie dostępu do nieistniejącego klucza tworzy go, wywołując funkcję fabrykującą (factory).

Python
from collections import defaultdict

gruppi = defaultdict(list)        # factory = list (empty list)
for nome in ["Ada", "Linus", "Ada", "Grace"]:
    gruppi[nome].append(1)
# defaultdict(list, {'Ada': [1, 1], 'Linus': [1], 'Grace': [1]})

Bez defaultdict musiałbyś zapisać:

Python
gruppi = {}
for nome in [...]:
    if nome not in gruppi:
        gruppi[nome] = []
    gruppi[nome].append(1)

Typowe fabryki: list, int (domyślnie 0), set, dict.

namedtuple: krotki z nazwanymi polami

Lekki sposób na tworzenie niezmiennych klas rekordów. Jest to krotka, ale z dostępem do pól poprzez nazwy.

Python
from collections import namedtuple

Punto = namedtuple("Punto", ["x", "y"])
p = Punto(3, 4)
p.x          # 3 (access by name)
p[0]         # 3 (access by index, still a tuple)
p.x + p.y    # 7

# typical use: return multiple values from a function
def divisione(a, b):
    Risultato = namedtuple("Risultato", ["quoziente", "resto"])
    return Risultato(a // b, a % b)

r = divisione(17, 5)
r.quoziente   # 3
r.resto       # 2

(W przypadku bardziej zaawansowanych zastosowań od wersji 3.7 dostępne są również dataclasses — patrz M9).

namedtuple: lekkie niezmienne rekordy

Moduł collections udostępnia również namedtuple, które pozwala szybko tworzyć lekkie obiekty przypominające klasy do przechowywania strukturyzowanych danych bez konieczności pisania konstruktorów czy powtarzalnych metod:

Python
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
p = Point(10, 20)
print(p.x, p.y)

Spróbuj sam

Ćwiczenie#python.m8.l3.e1
Próby: 0Ładowanie...

Dla danej listy `words = ['mela', 'pera', 'mela', 'kiwi', 'mela', 'pera']`, wyznacz najczęściej występujące słowo jako ciąg znaków w zmiennej `top`. Oceń `top`.

Ładowanie edytora...
Pokaż wskazówkę

Counter(...).most_common(1) zwraca listę w formacie [(słowo, licznik)].

Rozwiązanie dostępne po 3 próbach

Ćwiczenie powtórzeniowe

Ćwiczenie#python.m8.l3.e2
Próby: 0Ładowanie...

Dla podanych studentów `enrollments = [('Ada', 'mate'), ('Linus', 'fisica'), ('Ada', 'storia'), ('Grace', 'mate')]`, utwórz słownik `courses_per_student` jako defaultdict(list). Oceń `dict(courses_per_student)`.

Ładowanie edytora...
Pokaż wskazówkę

defaultdict(list), a następnie pętla for s, c in enrollments.

Rozwiązanie dostępne po 3 próbach

Dodatkowe wyzwanie

Ćwiczenie#python.m8.l3.e3
Próby: 0Ładowanie...

Zaimportuj `Counter` z modułu `collections`. Zlicz częstotliwość znaków w ciągu `text = "abracadabra"`. Zapisz licznik w zmiennej `char_counter` i oceń ją.

Ładowanie edytora...
Pokaż wskazówkę

Counter przyjmuje ciąg jako parametr i zlicza wystąpienia każdej litery.

Rozwiązanie dostępne po 3 próbach