Tiza Paso a paso
Practicar →

Pensamiento Computacional · Unidad 4 — Estructuras de datos

Diccionarios

Un diccionario guarda pares clave-valor. En vez de buscar por posición, buscás por nombre — y eso cambia todo.

Practicar este tema →8 ejercicios que te corrigen paso a paso · gratis, sin cuenta

La explicación

Buscar por nombre, no por número

notas = {"ana": 9, "luis": 4, "sol": 7}

notas["ana"]   → 9
len(notas)     → 3

Van con llaves, y cada elemento es clave: valor. La clave hace de índice, y en vez de ser un número puede ser un texto que significa algo.

Con una lista tendrías que guardar los nombres en una lista y las notas en otra, y mantener las posiciones sincronizadas. Con un diccionario la relación está adentro de la estructura, y buscar el alumno "ana" no requiere recorrer nada.

Agregar, cambiar, borrar

notas["pedro"] = 8   # si no existe, la crea
notas["ana"] = 10    # si existe, la pisa
del notas["luis"]    # la borra

Las claves son únicas: no puede haber dos "ana". Asignar sobre una clave existente reemplaza el valor.

La clave que no está

notas["pepe"]           → KeyError, el programa se corta
notas.get("pepe")      → None, sin error
notas.get("pepe", 0)   → 0, el valor por defecto
"pepe" in notas        → False
Esta es la causa número uno de programas que se cortan con diccionarios. Si no estás seguro de que la clave exista, usá get o preguntá con in antes. get con valor por defecto es especialmente cómodo para contar cosas.

Recorrer

for clave in notas:                # las claves
    print(clave, notas[clave])

for clave, valor in notas.items():  # las dos cosas
    print(clave, valor)

Ojo: for x in notas recorre las claves, no los valores. Es de lo que más confunde al principio. Si querés los valores sueltos, notas.values().

Contar cosas: el uso estrella

texto = "casa"
cuenta = {}
for letra in texto:
    cuenta[letra] = cuenta.get(letra, 0) + 1
print(cuenta)   # {'c': 1, 'a': 2, 's': 1}

La línea del medio es el idioma que conviene memorizar: "lo que había, o 0 si no había, más uno". Sin get habría que preguntar con un if cada vez.

Un ejercicio resuelto, paso a paso

Escribir una función que reciba una lista de palabras y devuelva un diccionario con cuántas veces aparece cada una.

El patrón de conteo, que sirve para esto y para mil cosas más:

def contar(palabras):
    cuenta = {}
    for p in palabras:
        cuenta[p] = cuenta.get(p, 0) + 1
    return cuenta

Con ["sol", "mar", "sol"]:

"sol" → no estaba: get devuelve 0, queda en 1
"mar" → no estaba: queda en 1
"sol" → ya estaba en 1: queda en 2

resultado: {"sol": 2, "mar": 1}

Por qué get(p, 0) y no cuenta[p]. La primera vez que aparece una palabra, la clave todavía no existe. Con corchetes eso sería un KeyError y el programa se cortaría en la primera palabra.

La versión sin get necesita un if y tres líneas donde había una:
if p in cuenta:
    cuenta[p] = cuenta[p] + 1
else:
    cuenta[p] = 1
Hace exactamente lo mismo. Vale conocer las dos, pero la de get es la que vas a ver escrita en todos lados.

Control: la suma de todos los valores del diccionario tiene que dar la cantidad de elementos de la lista original. Acá 2 + 1 = 3 ✓

Y uno del nivel del parcial

Escribir una función que reciba un texto y devuelva la palabra más repetida junto con la cantidad de veces que aparece. Si hay empate, tiene que devolver la primera en orden alfabético. Las mayúsculas no cuentan.

El ejercicio tiene tres partes: contar, encontrar el máximo, y resolver el empate. La tercera es la que casi nunca se hace y es la que el enunciado pide explícitamente.

1. Contar, con un diccionario:

cuenta = {}
for p in texto.lower().split():
    cuenta[p] = cuenta.get(p, 0) + 1

cuenta.get(p, 0) es el truco que evita el if: devuelve el valor guardado si la palabra ya está, y 0 si es la primera vez. Sin eso habría que escribir:

if p in cuenta:
    cuenta[p] = cuenta[p] + 1
else:
    cuenta[p] = 1

El .lower() antes del .split() es lo que hace que "El", "el" y "EL" cuenten como la misma palabra. Y .split() sin argumentos separa por cualquier cantidad de espacios, tabs o saltos de línea, que es lo que se quiere.

2 y 3. El máximo con desempate, en un solo recorrido:

mejor = None
for p in sorted(cuenta):
    if mejor is None or cuenta[p] > cuenta[mejor]:
        mejor = p

El truco está en recorrer las claves sorted. Como se visitan en orden alfabético y la comparación es > estricta, una palabra empatada nunca desplaza a la que ya está: la primera alfabética se queda. El desempate sale gratis, sin un if aparte.

Si la comparación fuera >=, ganaría la última alfabética, que es lo contrario de lo pedido. Ese solo carácter decide el ejercicio.

La función completa:

def mas_repetida(texto):
    cuenta = {}
    for p in texto.lower().split():
        cuenta[p] = cuenta.get(p, 0) + 1
    mejor = None
    for p in sorted(cuenta):
        if mejor is None or cuenta[p] > cuenta[mejor]:
            mejor = p
    return (mejor, cuenta[mejor]) if mejor else (None, 0)

Las pruebas:

"el gato y el perro y el gato"  → ("el", 3)
   el:3, gato:2, y:2, perro:1

"a b b a c"                     → ("a", 2)   empate entre a y b
"El el EL perro"             → ("el", 3)   mayúsculas
""                               → (None, 0)  texto vacío

El caso del empate es el que hay que probar sí o sí. Con "a b b a c" las dos palabras tienen 2 apariciones, y la respuesta correcta es "a" porque va antes alfabéticamente. Sin el sorted, el diccionario se recorre en el orden en que aparecieron las palabras en el texto, y en un empate ganaría la que apareció primero, que no tiene por qué ser la primera alfabética: con "b a a b c" ganaría "b".

Un control del conteo: la suma de todos los valores del diccionario tiene que dar la cantidad total de palabras del texto. En el primer ejemplo: 3 + 2 + 2 + 1 = 8, y el texto tiene 8 palabras ✓.

Dónde se pierde el punto: usar max(cuenta, key=cuenta.get) y entregarlo. Devuelve una palabra con el máximo, pero en caso de empate devuelve la que apareció primero en el texto, no la primera alfabética — y el enunciado pide una en particular.

Dónde se cae la mayoría

Hasta acá la explicación. La práctica es la otra mitad: 8 ejercicios de este tema, en cuatro niveles, que no te dicen sólo si está bien al final sino que te corrigen en cada paso y te explican por qué. Y uno para escribir el programa vos, que se prueba ejecutándolo en Python ahí mismo, en el navegador. Además trae una animación que muestra la idea en movimiento.

Practicar Diccionarios →

Dónde entra este tema en el parcial

Los otros temas de la unidad 4

Estructuras de datos

Ver todos los temas de Pensamiento Computacional