Vai al contenuto
eLearner.app
Modulo 8 · Lezione 3 di 431/36 nel corso~12 min
Lezioni del modulo (3/4)

collections: Counter e defaultdict

Il modulo collections aggiunge tipi di dati specializzati che estendono le collezioni built-in. I tre più usati: Counter, defaultdict, namedtuple.

Counter: conteggio frequenze

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 per chiavi assenti, NIENTE KeyError)
c.most_common(2)     # [('mela', 3), ('pera', 2)]

Funziona anche su stringhe (conta caratteri):

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

Supporta operazioni insiemistiche su conteggi (+, -, &, |) — molto comodo per aggregare conteggi di sorgenti diverse.

defaultdict: dict con default automatico

Un dict che, quando accedi a una chiave inesistente, la crea chiamando una factory.

Python
from collections import defaultdict

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

Senza defaultdict, dovresti scrivere:

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

Factory comuni: list, int (default 0), set, dict.

namedtuple: tuple con nomi di campo

Un modo leggero per creare classi-record immutabili. È una tuple, ma con accesso ai campi per nome.

Python
from collections import namedtuple

Punto = namedtuple("Punto", ["x", "y"])
p = Punto(3, 4)
p.x          # 3 (accesso per nome)
p[0]         # 3 (accesso per indice, sempre tuple)
p.x + p.y    # 7

# tipico per ritornare più valori da una funzione
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

(Per casi più sofisticati esiste anche dataclasses dalla 3.7 — vedi M9.)

namedtuple: record immutabili leggeri

Il modulo collections offre anche namedtuple, che permette di creare velocemente oggetti leggeri simili a classi per memorizzare dati senza dover scrivere costruttori e metodi:

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

Prova tu

Esercizio#python.m8.l3.e1
Tentativi: 0Caricamento…

Data la lista `words = ['mela', 'pera', 'mela', 'kiwi', 'mela', 'pera']`, calcola la parola più frequente in `top` come stringa. Valuta `top`.

Caricamento editor…
Mostra suggerimento

Counter(...).most_common(1) ritorna [(parola, conteggio)].

Soluzione disponibile dopo 3 tentativi

Esercizio di ripasso

Esercizio#python.m8.l3.e2
Tentativi: 0Caricamento…

Dati gli studenti `enrollments = [('Ada', 'mate'), ('Linus', 'fisica'), ('Ada', 'storia'), ('Grace', 'mate')]`, costruisci `courses_per_student` come defaultdict(list). Valuta `dict(courses_per_student)`.

Caricamento editor…
Mostra suggerimento

defaultdict(list) poi for s, c in enrollments.

Soluzione disponibile dopo 3 tentativi

Sfida aggiuntiva

Esercizio#python.m8.l3.e3
Tentativi: 0Caricamento…

Importa `Counter` da `collections`. Conta la frequenza dei caratteri della stringa `text = "abracadabra"`. Salva il contatore in `char_counter` e valutalo.

Caricamento editor…
Mostra suggerimento

Counter accetta come parametro la stringa stessa e conta la frequenza di ogni lettera.

Soluzione disponibile dopo 3 tentativi