Lecciones del módulo (3/4)
collections: Counter y defaultdict
El módulo collections añade tipos de datos especializados que extienden las colecciones integradas. Los tres más utilizados son: Counter, defaultdict y namedtuple.
Counter: conteo de frecuencia
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)]También funciona con cadenas de texto (cuenta caracteres):
Counter("ciao mondo")
# Counter({'o': 2, 'c': 1, 'i': 1, 'a': 1, ' ': 1, 'm': 1, 'n': 1, 'd': 1})Soporta operaciones similares a conjuntos sobre los conteos (+, -, &, |), lo cual es muy útil para agregar conteos de diferentes fuentes.
defaultdict: diccionario con valor por defecto automático
Un diccionario que, cuando accedes a una clave inexistente, la crea llamando a una fábrica (factory).
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]})Sin defaultdict, tendrías que escribir:
gruppi = {}
for nome in [...]:
if nome not in gruppi:
gruppi[nome] = []
gruppi[nome].append(1)Fábricas comunes: list, int (por defecto 0), set, dict.
namedtuple: tuplas con nombres de campos
Una forma ligera de crear clases de registro inmutables. Es una tupla, pero con acceso a los campos por nombre.
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(Para casos más sofisticados también existe dataclasses desde la versión 3.7; ver M9).
namedtuple: registros inmutables ligeros
El módulo collections también exporta namedtuple, que te permite construir rápidamente objetos ligeros similares a clases para almacenar datos estructurados sin tener que escribir constructores ni métodos repetitivos:
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
p = Point(10, 20)
print(p.x, p.y)Pruébalo
Dada la lista `words = ['mela', 'pera', 'mela', 'kiwi', 'mela', 'pera']`, calcula la palabra más frecuente en `top` como una cadena de texto. Evalúa `top`.
Mostrar pista
Counter(...).most_common(1) devuelve [(palabra, cuenta)].
Solución disponible después de 3 intentos
Ejercicio de repaso
Dados los estudiantes `enrollments = [('Ada', 'mate'), ('Linus', 'fisica'), ('Ada', 'storia'), ('Grace', 'mate')]`, construye `courses_per_student` como un defaultdict(list). Evalúa `dict(courses_per_student)`.
Mostrar pista
defaultdict(list) y luego for s, c in enrollments.
Solución disponible después de 3 intentos
Desafío adicional
Importa `Counter` de `collections`. Cuenta la frecuencia de caracteres en la cadena `text = "abracadabra"`. Guarda el contador en `char_counter` y evalúalo.
Mostrar pista
Counter toma la cadena como parámetro y cuenta las apariciones de cada letra.
Solución disponible después de 3 intentos