Quiz: Estructuras de Datos
🧭 Navegación:
- Anterior: Conjuntos (Sets)
- Siguiente: Funciones y Módulos
- Volver al Índice de Estructuras de Datos
¡Es hora de poner a prueba tus conocimientos sobre las estructuras de datos en Python! Este quiz cubre los conceptos clave de listas, diccionarios, tuplas y conjuntos que hemos explorado en este capítulo.
Instrucciones
- Lee cada pregunta cuidadosamente
- Intenta responder antes de ver la solución
- Las soluciones están ocultas bajo cada pregunta
- Al final encontrarás una evaluación basada en tus respuestas correctas
¡Buena suerte!
Preguntas Teóricas
1. Analogías del Almacén
¿Qué estructura de datos corresponde a cada analogía del almacén?
a) Estanterías flexibles que pueden reorganizarse
b) Sistema de inventario con etiquetas
c) Paquetes sellados que no pueden modificarse
d) Estaciones de clasificación sin duplicados
Ver respuesta
Respuestas correctas:
- a) Listas: Estanterías flexibles que pueden reorganizarse
- b) Diccionarios: Sistema de inventario con etiquetas
- c) Tuplas: Paquetes sellados que no pueden modificarse
- d) Conjuntos: Estaciones de clasificación sin duplicados
Estas analogías nos ayudan a entender el propósito y comportamiento de cada estructura de datos:
- Las listas son flexibles y ordenadas, como estanterías que podemos reorganizar
- Los diccionarios permiten acceso rápido por clave, como un sistema de inventario
- Las tuplas son inmutables, como paquetes sellados
- Los conjuntos eliminan duplicados automáticamente, como estaciones de clasificación
2. Mutabilidad vs Inmutabilidad
¿Cuáles de las siguientes afirmaciones son correctas sobre la mutabilidad de las estructuras de datos?
a) Las listas son mutables y pueden contener cualquier tipo de dato
b) Los diccionarios son inmutables una vez creados
c) Las tuplas son inmutables pero pueden contener objetos mutables
d) Los conjuntos son mutables pero solo pueden contener objetos inmutables
Ver respuesta
Respuestas correctas: a), c) y d)
Explicación:
- ✅ Las listas son mutables y pueden contener cualquier tipo de dato
- ❌ Los diccionarios son mutables, no inmutables
- ✅ Las tuplas son inmutables pero pueden contener objetos mutables (como listas)
- ✅ Los conjuntos son mutables pero solo pueden contener objetos inmutables (números, strings, tuplas)
Ejemplo con tuplas conteniendo objetos mutables:
# La tupla es inmutable, pero la lista dentro de ella es mutable
t = (1, [2, 3], 4)
t[1].append(5) # Válido
print(t) # (1, [2, 3, 5], 4)
# Pero no podemos cambiar la tupla en sí
try:
t[1] = [6, 7] # Esto generará un error
except TypeError as e:
print(f"Error: {e}")
3. Eficiencia de Operaciones
Ordena las siguientes operaciones de más eficiente a menos eficiente:
a) Buscar un elemento en una lista
b) Buscar una clave en un diccionario
c) Verificar si un elemento está en un conjunto
d) Buscar un elemento en una tupla
Ver respuesta
Orden correcto (de más eficiente a menos eficiente):
- b) y c) - Buscar en diccionario y conjunto: O(1)
- a) y d) - Buscar en lista y tupla: O(n)
Explicación:
- Los diccionarios y conjuntos usan tablas hash, permitiendo búsquedas en tiempo constante O(1)
- Las listas y tuplas requieren búsqueda lineal O(n), revisando cada elemento
- Las tuplas no son más rápidas que las listas para búsquedas, aunque son más eficientes en memoria
# Ejemplo de rendimiento
import time
def medir_tiempo(operacion, n=1000000):
inicio = time.time()
operacion()
return time.time() - inicio
# Preparar estructuras
lista = list(range(n))
conjunto = set(lista)
diccionario = {x: x for x in lista}
elemento = n - 1 # Peor caso
# Medir tiempos
tiempo_lista = medir_tiempo(lambda: elemento in lista)
tiempo_conjunto = medir_tiempo(lambda: elemento in conjunto)
tiempo_dict = medir_tiempo(lambda: elemento in diccionario)
print(f"Tiempo lista: {tiempo_lista:.6f}s")
print(f"Tiempo conjunto: {tiempo_conjunto:.6f}s")
print(f"Tiempo diccionario: {tiempo_dict:.6f}s")
Preguntas Prácticas
4. Manipulación de Listas
¿Qué imprimirá el siguiente código?
lista = [1, 2, 3, 4, 5]
lista[1:4] = [10]
print(lista)
Ver respuesta
Respuesta: [1, 10, 5]
Explicación:
- La lista original es
[1, 2, 3, 4, 5]
- El slice
[1:4]
selecciona los elementos en los índices 1, 2 y 3 - Estos tres elementos son reemplazados por un solo elemento
[10]
- El resultado es
[1, 10, 5]
Este ejemplo demuestra que:
- Los slices pueden ser reemplazados por un número diferente de elementos
- La lista se ajusta automáticamente al nuevo tamaño
- Los elementos fuera del slice permanecen sin cambios
5. Diccionarios Anidados
Dado el siguiente diccionario:
almacen = {
'electrónicos': {
'computadoras': {'stock': 10, 'precio': 1200},
'tablets': {'stock': 15, 'precio': 300}
},
'muebles': {
'sillas': {'stock': 20, 'precio': 50},
'mesas': {'stock': 8, 'precio': 150}
}
}
Escribe una función que calcule el valor total del inventario.
Ver respuesta
Solución:
def valor_total_inventario(inventario):
total = 0
for categoria in inventario.values():
for producto in categoria.values():
total += producto['stock'] * producto['precio']
return total
# Calcular el valor total
total = valor_total_inventario(almacen)
print(f"Valor total del inventario: ${total:,}") # $19,200
Explicación:
- La función recorre cada categoría del almacén
- Para cada categoría, recorre cada producto
- Multiplica el stock por el precio de cada producto
- Suma todos los valores para obtener el total
Alternativa usando comprensión de diccionarios:
def valor_total_inventario_comprension(inventario):
return sum(
producto['stock'] * producto['precio']
for categoria in inventario.values()
for producto in categoria.values()
)
6. Tuplas y Desempaquetado
¿Qué valores tendrán las variables después de ejecutar este código?
datos = [(1, 'a'), (2, 'b'), (3, 'c')]
numeros, letras = zip(*datos)
print(numeros)
print(letras)
Ver respuesta
Respuesta:
numeros = (1, 2, 3)
letras = ('a', 'b', 'c')
Explicación:
zip(*datos)
desempaqueta la lista de tuplas- El operador
*
desempaquetadatos
en argumentos individuales zip()
crea un nuevo iterador que agrupa los elementos por posición- El resultado se asigna a
numeros
yletras
mediante desempaquetado
Este patrón es útil para:
- Transponer matrices
- Separar datos en columnas
- Procesar datos estructurados
Ejemplo adicional:
# Crear una lista de tuplas desde columnas separadas
nums = [1, 2, 3]
lets = ['a', 'b', 'c']
combinados = list(zip(nums, lets))
print(combinados) # [(1, 'a'), (2, 'b'), (3, 'c')]
# Volver a separar
n, l = zip(*combinados)
print(n) # (1, 2, 3)
print(l) # ('a', 'b', 'c')
7. Operaciones con Conjuntos
Dado el siguiente código:
empleados_python = {'Ana', 'Carlos', 'Diana', 'Eduardo'}
empleados_java = {'Bruno', 'Carlos', 'Diana', 'Fernando'}
empleados_javascript = {'Carlos', 'Gabriel', 'Diana', 'Helena'}
Escribe expresiones para encontrar:
a) Empleados que conocen los tres lenguajes
b) Empleados que solo conocen Python
c) Empleados que conocen al menos dos lenguajes
Ver respuesta
Solución:
# a) Empleados que conocen los tres lenguajes
todos_lenguajes = empleados_python & empleados_java & empleados_javascript
print(f"Conocen los tres lenguajes: {todos_lenguajes}") # {'Carlos', 'Diana'}
# b) Empleados que solo conocen Python
solo_python = empleados_python - (empleados_java | empleados_javascript)
print(f"Solo conocen Python: {solo_python}") # {'Ana'}
# c) Empleados que conocen al menos dos lenguajes
python_java = empleados_python & empleados_java
python_js = empleados_python & empleados_javascript
java_js = empleados_java & empleados_javascript
al_menos_dos = python_java | python_js | java_js
print(f"Conocen al menos dos lenguajes: {al_menos_dos}") # {'Carlos', 'Diana'}
Explicación de operadores:
&
: intersección (elementos comunes)|
: unión (todos los elementos)-
: diferencia (elementos en el primer conjunto pero no en el segundo)
Alternativa usando métodos:
# Los mismos resultados usando métodos
todos_lenguajes = empleados_python.intersection(empleados_java, empleados_javascript)
solo_python = empleados_python.difference(empleados_java.union(empleados_javascript))
al_menos_dos = (empleados_python.intersection(empleados_java)
.union(empleados_python.intersection(empleados_javascript))
.union(empleados_java.intersection(empleados_javascript)))
8. Proyecto Práctico: Sistema de Inventario
Implementa un sistema simple de inventario que permita:
- Añadir productos con cantidad y precio
- Actualizar el stock
- Calcular el valor total del inventario
- Listar productos con bajo stock (menos de 5 unidades)
Ver respuesta
Solución:
class Inventario:
def __init__(self):
self.productos = {}
def agregar_producto(self, codigo, nombre, cantidad, precio):
"""Añade un nuevo producto o actualiza uno existente."""
self.productos[codigo] = {
'nombre': nombre,
'cantidad': cantidad,
'precio': precio
}
def actualizar_stock(self, codigo, cantidad):
"""Actualiza la cantidad de un producto."""
if codigo in self.productos:
self.productos[codigo]['cantidad'] += cantidad
return True
return False
def valor_total(self):
"""Calcula el valor total del inventario."""
return sum(
prod['cantidad'] * prod['precio']
for prod in self.productos.values()
)
def productos_bajo_stock(self, limite=5):
"""Lista productos con stock menor al límite."""
return {
codigo: datos
for codigo, datos in self.productos.items()
if datos['cantidad'] < limite
}
def mostrar_inventario(self):
"""Muestra el inventario completo."""
print("\nInventario Actual:")
print("-" * 50)
print(f"{'Código':<10} {'Nombre':<20} {'Cantidad':<10} {'Precio':>8}")
print("-" * 50)
for codigo, datos in self.productos.items():
print(f"{codigo:<10} {datos['nombre']:<20} {datos['cantidad']:<10} ${datos['precio']:>7.2f}")
print("-" * 50)
print(f"Valor total del inventario: ${self.valor_total():,.2f}")
# Ejemplo de uso
inventario = Inventario()
# Agregar productos
inventario.agregar_producto('LAP001', 'Laptop Dell', 10, 1200)
inventario.agregar_producto('MON001', 'Monitor 24"', 15, 200)
inventario.agregar_producto('TEC001', 'Teclado Mecánico', 3, 80)
inventario.agregar_producto('MOU001', 'Mouse Inalámbrico', 20, 30)
# Mostrar inventario inicial
inventario.mostrar_inventario()
# Actualizar stock
inventario.actualizar_stock('LAP001', -2) # Venta de 2 laptops
inventario.actualizar_stock('MON001', 5) # Recepción de 5 monitores
# Mostrar productos con bajo stock
print("\nProductos con bajo stock:")
for codigo, datos in inventario.productos_bajo_stock().items():
print(f"{datos['nombre']}: {datos['cantidad']} unidades")
# Mostrar inventario actualizado
inventario.mostrar_inventario()
Este ejemplo demuestra:
- Uso de diccionarios anidados para almacenar datos
- Métodos para manipular el inventario
- Comprensiones de diccionarios para filtrar datos
- Formateo de strings para presentación
Características adicionales que podrías implementar:
- Validación de datos (cantidades no negativas, precios válidos)
- Historial de transacciones usando tuplas
- Categorización de productos usando conjuntos
- Búsqueda de productos por nombre o código
9. Desafío: Análisis de Datos
Dado un conjunto de datos de ventas, escribe funciones para:
- Encontrar los productos más vendidos
- Calcular las ventas por día
- Identificar patrones de compra (productos que se compran juntos)
ventas = [
('2023-07-01', ['laptop', 'mouse', 'teclado']),
('2023-07-01', ['monitor', 'teclado']),
('2023-07-02', ['laptop', 'monitor']),
('2023-07-02', ['mouse', 'teclado', 'auriculares']),
('2023-07-03', ['laptop', 'mouse'])
]
Ver respuesta
Solución:
from collections import Counter
from itertools import combinations
def productos_mas_vendidos(ventas):
"""Encuentra los productos más vendidos y su cantidad."""
contador = Counter()
for _, productos in ventas:
contador.update(productos)
return contador.most_common()
def ventas_por_dia(ventas):
"""Calcula el número de ventas por día."""
ventas_dia = {}
for fecha, productos in ventas:
ventas_dia[fecha] = ventas_dia.get(fecha, 0) + 1
return dict(sorted(ventas_dia.items()))
def productos_relacionados(ventas, min_frecuencia=2):
"""Identifica productos que se compran juntos frecuentemente."""
pares = Counter()
for _, productos in ventas:
# Generar todos los pares posibles de productos
for par in combinations(sorted(productos), 2):
pares[par] += 1
# Filtrar pares que aparecen al menos min_frecuencia veces
return {par: freq for par, freq in pares.items()
if freq >= min_frecuencia}
# Análisis de ventas
print("Productos más vendidos:")
for producto, cantidad in productos_mas_vendidos(ventas):
print(f"{producto}: {cantidad} ventas")
print("\nVentas por día:")
for fecha, cantidad in ventas_por_dia(ventas).items():
print(f"{fecha}: {cantidad} ventas")
print("\nProductos frecuentemente comprados juntos:")
for (prod1, prod2), freq in productos_relacionados(ventas).items():
print(f"{prod1} + {prod2}: {freq} veces")
Este ejemplo demuestra:
- Uso de
Counter
para contar ocurrencias - Diccionarios para agrupar datos por fecha
- Combinaciones para analizar patrones
- Comprensiones de diccionarios para filtrar resultados
Mejoras posibles:
- Añadir análisis de tendencias temporales
- Calcular correlaciones entre productos
- Visualizar datos con gráficos
- Generar recomendaciones basadas en patrones
10. Desafío Final: Optimización de Código
Optimiza el siguiente código que procesa datos de ventas:
def procesar_ventas(ventas):
productos_vendidos = []
ventas_por_producto = {}
clientes_por_producto = {}
for venta in ventas:
producto = venta['producto']
cantidad = venta['cantidad']
cliente = venta['cliente']
productos_vendidos.append(producto)
if producto in ventas_por_producto:
ventas_por_producto[producto] += cantidad
else:
ventas_por_producto[producto] = cantidad
if producto not in clientes_por_producto:
clientes_por_producto[producto] = []
if cliente not in clientes_por_producto[producto]:
clientes_por_producto[producto].append(cliente)
return (list(set(productos_vendidos)),
ventas_por_producto,
clientes_por_producto)
Ver respuesta
Solución optimizada:
from collections import defaultdict
def procesar_ventas_optimizado(ventas):
"""
Procesa datos de ventas de manera eficiente.
Args:
ventas: Lista de diccionarios con datos de ventas
Returns:
Tupla con (productos únicos, ventas por producto, clientes por producto)
"""
productos_vendidos = set() # Usar set desde el inicio
ventas_por_producto = defaultdict(int) # Valor default 0
clientes_por_producto = defaultdict(set) # Valor default set()
for venta in ventas:
producto = venta['producto']
productos_vendidos.add(producto)
ventas_por_producto[producto] += venta['cantidad']
clientes_por_producto[producto].add(venta['cliente'])
return (list(productos_vendidos),
dict(ventas_por_producto),
{k: list(v) for k, v in clientes_por_producto.items()})
# Comparación de rendimiento
import time
# Datos de prueba
datos_prueba = [
{'producto': 'laptop', 'cantidad': 1, 'cliente': 'Ana'},
{'producto': 'monitor', 'cantidad': 2, 'cliente': 'Bruno'},
{'producto': 'laptop', 'cantidad': 1, 'cliente': 'Carlos'},
{'producto': 'teclado', 'cantidad': 3, 'cliente': 'Ana'},
{'producto': 'monitor', 'cantidad': 1, 'cliente': 'Diana'}
]
# Medir tiempo de la versión original
inicio = time.time()
resultado_original = procesar_ventas(datos_prueba)
tiempo_original = time.time() - inicio
# Medir tiempo de la versión optimizada
inicio = time.time()
resultado_optimizado = procesar_ventas_optimizado(datos_prueba)
tiempo_optimizado = time.time() - inicio
print(f"Tiempo versión original: {tiempo_original:.6f}s")
print(f"Tiempo versión optimizada: {tiempo_optimizado:.6f}s")
print(f"Mejora: {(tiempo_original/tiempo_optimizado):.2f}x más rápido")
Mejoras realizadas:
- Uso de
set()
desde el inicio para productos únicos - Uso de
defaultdict
para evitar verificaciones de existencia - Uso de
set()
para clientes por producto, eliminando duplicados automáticamente - Conversión final a los tipos de datos requeridos
Ventajas:
- Código más conciso y legible
- Mejor rendimiento
- Menos propenso a errores
- Más eficiente en memoria
La versión optimizada es especialmente más eficiente con conjuntos de datos grandes debido a:
- Menos operaciones de verificación
- Uso de estructuras de datos optimizadas
- Mejor manejo de memoria
Evaluación
Cuenta tus respuestas correctas:
- 9-10 correctas: ¡Excelente! Dominas las estructuras de datos en Python.
- 7-8 correctas: ¡Muy bien! Tienes una comprensión sólida.
- 5-6 correctas: Bien. Entiendes los conceptos básicos pero necesitas más práctica.
- 3-4 correctas: Regular. Repasa los conceptos clave.
- 0-2 correctas: Necesitas revisar el capítulo nuevamente.
Próximos Pasos
- Revisa los conceptos en los que tuviste dificultades
- Practica con los ejercicios adicionales de cada sección
- Intenta resolver problemas reales usando estas estructuras
- Avanza al siguiente capítulo: Funciones y Módulos
🧭 Navegación:
- Anterior: Conjuntos (Sets)
- Siguiente: Funciones y Módulos
- Volver al Índice de Estructuras de Datos