Saltar al contenido
Editor

Listas y diccionarios anidados en Python: datos complejos

Intermedio25 min6 ejercicios85 XP

Esta lección es una traducción del original en inglés.Read in EnglishAvisar de un error de traducción

0/6 ejercicios

Piensa en una escuela. Una escuela tiene aulas. Cada aula tiene estudiantes. Cada estudiante tiene un nombre, una edad y una lista de notas. Son datos dentro de datos dentro de datos: datos anidados.

Los datos anidados están en todas partes en la programación real. Una red social guarda usuarios que tienen publicaciones, y cada publicación tiene comentarios. Un juego guarda niveles que contienen enemigos, y cada enemigo tiene sus estadísticas. Una tienda en línea tiene categorías con productos que tienen reseñas.

En este tutorial aprenderás a crear, leer, modificar y recorrer listas y diccionarios anidados. Son habilidades esenciales para trabajar con datos reales, sobre todo con el JSON que devuelven las API web.

¿Cómo funcionan las listas dentro de listas?

Una lista puede contener otras listas como elementos. Esto crea una estructura bidimensional, como una cuadrícula o una tabla. Piensa en una hoja de cálculo, con sus filas y columnas.

Una lista anidada que representa una cuadrícula
# A 3x3 grid (like a tic-tac-toe board)
board = [
['X', 'O', 'X'],
['O', 'X', 'O'],
['X', ' ', 'O'],
]
for row in board:
print(row)
Salida
['X', 'O', 'X']
['O', 'X', 'O']
['X', ' ', 'O']

Para acceder a un elemento de una lista anidada, usas dos pares de corchetes. El primer corchete elige la fila. El segundo corchete elige la columna.

Acceder a elementos con doble índice
board = [
['X', 'O', 'X'],
['O', 'X', 'O'],
['X', ' ', 'O'],
]
# board[row][column]
print(board[0][0]) # X (top-left)
print(board[1][1]) # X (center)
print(board[2][1]) # (space) (bottom-middle)
Salida
X
X

También puedes modificar elementos con la misma sintaxis de doble corchete. Así es como colocarías una jugada en una partida de tres en raya.

Modificar elementos de una lista anidada
board = [
[' ', ' ', ' '],
[' ', ' ', ' '],
[' ', ' ', ' '],
]
# Place some moves
board[0][0] = 'X' # top-left
board[1][1] = 'O' # center
board[0][2] = 'X' # top-right
for row in board:
print(row)
Salida
['X', ' ', 'X']
[' ', 'O', ' ']
[' ', ' ', ' ']

¿Cómo funcionan los diccionarios anidados?

El valor de un diccionario puede ser, a su vez, otro diccionario. Esto crea una estructura en forma de árbol en la que bajas de clave en clave hasta llegar a los datos que necesitas.

Diccionarios anidados con acceso encadenado por claves
school = {
'Room 101': {
'teacher': 'Ms. Smith',
'subject': 'Math',
'students': 28,
},
'Room 102': {
'teacher': 'Mr. Jones',
'subject': 'English',
'students': 25,
},
}
print(school['Room 101']['teacher']) # Ms. Smith
print(school['Room 102']['students']) # 25
Salida
Ms. Smith
25

Cada par de corchetes baja un nivel más. school['Room 101'] te da el diccionario interno. Luego ['teacher'] te da el valor que hay dentro de ese diccionario interno.

También puedes añadir claves nuevas o actualizar valores en cualquier nivel.

Modificar diccionarios anidados
school = {
'Room 101': {
'teacher': 'Ms. Smith',
'subject': 'Math',
},
}
# Update an existing value
school['Room 101']['subject'] = 'Algebra'
# Add a new key to the inner dict
school['Room 101']['students'] = 30
# Add an entirely new room
school['Room 103'] = {
'teacher': 'Ms. Lee',
'subject': 'Science',
'students': 22,
}
for room, info in school.items():
print(f"{room}: {info['teacher']} teaches {info['subject']}")
Salida
Room 101: Ms. Smith teaches Algebra
Room 103: Ms. Lee teaches Science

Listas de diccionarios: el patrón más común

La estructura anidada más común en la programación real es una lista de diccionarios. Cada diccionario representa un registro (un estudiante, un producto, un usuario) y la lista reúne todos los registros.

Si alguna vez has visto datos de una API web o de una base de datos, casi siempre tienen la forma de una lista de diccionarios.

Una lista de diccionarios: registros de estudiantes
students = [
{'name': 'Alice', 'age': 15, 'grade': 92},
{'name': 'Bob', 'age': 16, 'grade': 85},
{'name': 'Charlie', 'age': 15, 'grade': 97},
]
# Access a specific student
print(students[0]['name']) # Alice
print(students[2]['grade']) # 97
# Loop through all students
for student in students:
print(f"{student['name']} is {student['age']} and scored {student['grade']}")
Salida
Alice
97
Alice is 15 and scored 92
Bob is 16 and scored 85
Charlie is 15 and scored 97

El patrón siempre es list[index][key]. El índice elige el diccionario. La clave elige el valor dentro de ese diccionario.

Cómo acceder de forma segura a datos muy anidados

Los datos reales pueden tener varios niveles de anidación. Una empresa tiene departamentos, cada departamento tiene equipos y cada equipo tiene miembros. Para acceder a datos muy anidados, encadenas varios corchetes.

Encadenar corchetes para llegar al fondo
company = {
'engineering': {
'backend': {
'members': ['Alice', 'Bob'],
'lead': 'Alice',
},
'frontend': {
'members': ['Charlie', 'Diana'],
'lead': 'Charlie',
},
},
}
# Get the backend team lead
print(company['engineering']['backend']['lead']) # Alice
# Get the second frontend team member
print(company['engineering']['frontend']['members'][1]) # Diana
Salida
Alice
Diana

El peligro de anidar mucho es que cualquier clave que falte provoca un KeyError. Si los datos pueden estar incompletos, usa el método .get(), que devuelve None (o un valor predeterminado) en vez de detener el programa con un error.

Acceso anidado seguro con .get()
user = {
'name': 'Alice',
'profile': {
'bio': 'Python developer',
},
}
# Safe access with .get()
print(user.get('profile', {}).get('bio', 'No bio')) # Python developer
print(user.get('profile', {}).get('website', 'No site')) # No site
print(user.get('settings', {}).get('theme', 'default')) # default
Salida
Python developer
No site
default

Cómo recorrer estructuras de datos anidadas

Cuando tienes datos anidados, a menudo necesitas bucles anidados. El bucle exterior recorre los elementos del nivel superior y el bucle interior recorre los elementos que hay dentro de cada uno.

Recorrer un diccionario de listas
# A class with students and their grades
classes = {
'Math': [85, 92, 78, 95],
'English': [88, 76, 91],
'Science': [93, 87, 82, 79, 95],
}
for subject, grades in classes.items():
average = sum(grades) / len(grades)
print(f"{subject}: average = {average:.1f}")
Salida
Math: average = 87.5
English: average = 85.0
Science: average = 87.2
Recorrer una cuadrícula 2D con enumerate
# Nested list: a grid of numbers
grid = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
]
# Print each number with its position
for row_index, row in enumerate(grid):
for col_index, value in enumerate(row):
print(f"grid[{row_index}][{col_index}] = {value}")
Salida
grid[0][0] = 1
grid[0][1] = 2
grid[0][2] = 3
grid[1][0] = 4
grid[1][1] = 5
grid[1][2] = 6
grid[2][0] = 7
grid[2][1] = 8
grid[2][2] = 9

Con las listas de diccionarios suele bastar un solo bucle, porque cada diccionario es un registro completo.

Filtrar una lista de diccionarios revisando listas anidadas
products = [
{'name': 'Laptop', 'price': 999, 'tags': ['electronics', 'computers']},
{'name': 'Book', 'price': 15, 'tags': ['education', 'reading']},
{'name': 'Phone', 'price': 699, 'tags': ['electronics', 'mobile']},
]
# Find all electronics
for product in products:
if 'electronics' in product['tags']:
print(f"{product['name']}: ${product['price']}")
Salida
Laptop: $999
Phone: $699

Cómo crear estructuras de datos anidadas desde cero

No siempre recibes los datos anidados ya hechos: a veces tienes que construirlos tú. Un patrón común es empezar con una estructura vacía e ir añadiendo elementos dentro de un bucle.

Crear un diccionario de listas agrupando datos
# Build a dictionary that groups words by their first letter
words = ['apple', 'avocado', 'banana', 'blueberry', 'cherry', 'coconut']
by_letter = {}
for word in words:
first = word[0]
if first not in by_letter:
by_letter[first] = []
by_letter[first].append(word)
for letter, group in by_letter.items():
print(f"{letter}: {group}")
Salida
a: ['apple', 'avocado']
b: ['banana', 'blueberry']
c: ['cherry', 'coconut']

Otra tarea común es convertir datos planos en estructuras anidadas. Por ejemplo, convertir una lista plana de puntuaciones en una lista de diccionarios.

Combinar listas paralelas en una lista de diccionarios
# Transform parallel lists into a list of dicts
names = ['Alice', 'Bob', 'Charlie']
ages = [15, 16, 15]
grades = [92, 85, 97]
students = []
for i in range(len(names)):
student = {
'name': names[i],
'age': ages[i],
'grade': grades[i],
}
students.append(student)
for s in students:
print(s)
Salida
{'name': 'Alice', 'age': 15, 'grade': 92}
{'name': 'Bob', 'age': 16, 'grade': 85}
{'name': 'Charlie', 'age': 15, 'grade': 97}

Ejercicios de práctica

Accede a elementos de una lista anidada
Escribe el código

Tienes una cuadrícula de números de 3x3. Imprime el valor central (fila 1, columna 1) y después el valor de la esquina inferior derecha (fila 2, columna 2). Cada uno en una línea aparte.

grid = [
[10, 20, 30],
[40, 50, 60],
[70, 80, 90],
]
# Print the center value
# Print the bottom-right value
Predice la salida: acceso a un diccionario anidado
Predice la salida

Lee el código con atención. ¿Qué va a imprimir? Escribe la salida exacta.

data = {
'user': {
'name': 'Alice',
'scores': [80, 90, 100],
},
}
print(data['user']['name'])
print(data['user']['scores'][2])
Encuentra al estudiante con la nota más alta
Escribe el código

Recorre la lista de estudiantes y encuentra al que tiene la nota más alta. Imprime su nombre y su nota con el formato: Best: Name (Grade)

students = [
{'name': 'Alice', 'grade': 88},
{'name': 'Bob', 'grade': 95},
{'name': 'Charlie', 'grade': 72},
{'name': 'Diana', 'grade': 91},
]
# Find and print the highest scorer
Agrupa palabras por su primera letra
Escribe el código

Agrupa las palabras en un diccionario según su primera letra. Luego imprime cada grupo en una línea aparte con el formato: letter: [words]

Imprime las letras en orden alfabético.

words = ['ant', 'bear', 'apple', 'bat', 'cat', 'cow']
# Group by first letter and print
Corrige el error: la trampa de las listas anidadas
Corrige el error

Este código intenta crear una cuadrícula de 3x3 y poner "X" solo en la celda central. Pero algo falla: ¡ejecútalo y verás! Corrige el error para que solo la celda central sea "X" y todas las demás sigan siendo ".".

Imprime cada fila en una línea aparte.

row = ['.'] * 3
grid = [row] * 3
grid[1][1] = 'X'
for r in grid:
print(r)
Calcula el promedio de cada clase
Escribe el código

Tienes un diccionario en el que cada clave es el nombre de una clase y cada valor es una lista de diccionarios de estudiantes. Calcula la nota promedio de cada clase e imprímela con el formato: ClassName: average

Redondea cada promedio a 1 decimal. Imprime las clases en orden alfabético.

classes = {
'Math': [
{'name': 'Alice', 'grade': 90},
{'name': 'Bob', 'grade': 80},
],
'English': [
{'name': 'Charlie', 'grade': 85},
{'name': 'Diana', 'grade': 95},
{'name': 'Eve', 'grade': 78},
],
}
# Calculate and print each class average

Tutoriales relacionados

¿Te sirvió este tutorial?

Sugerir una mejora