5. Estructuras de datos#

5.1. Listas#

Las listas son estructuras de datos que pueden almacenar cualquier otro tipo de dato, inclusive una lista puede contener otra lista, además, la cantidad de elementos de una lista se puede modificar removiendo o añadiendo elementos. Para definir una lista se utilizan los corchetes, dentro de estos se colocan todos los elementos separados por comas:

nombres = ["Ana","Juan","Sofía","Pablo","Tania"]
print(type(nombres))
<class 'list'>

Recordar que podemos crear listas con diferentes tipos de datos, por ejemplo, la siguiente lista contiene tres objetos: uno de tipo string, un entero y un booleano.

varios = ["Hola", 200, True]
print(type(varios))
<class 'list'>

La cantidad de elementos que conforman una lista se puede determinar utilizando la función len:

puntuaciones = [10, 8, 9, 9.5, 7]
len(puntuaciones)
5

5.1.1. Acceder a los elementos de una lista#

Las listas son secuencias y por lo tanto se puede acceder a sus elementos mediante indexación, es decir, con la notación:

lista[k]

Donde k es el índice correspondiente al elemento que se quiere acceder y lista el nombre de la variable en la cual está almacenada la lista. Veamos el siguiente ejemplo:

nombres = ["Ana","Juan","Amelia","Pablo"]
nombres[2]
'Amelia'

En lo anterior accedemos al elemento ubicado en el índice 2, es decir, el tercer elemento. En la siguiente figura podemos observar una representación gráfica de la lista nombres con sus elementos y los índices correspondientes (en color naranja) a cada uno de ellos.

El último elemento de una lista se puede obtener siempre utilizando el índice negativo -1:

nombres[-1]
'Pablo'

5.1.2. Modificar elementos de una lista#

Las listas son estructuras de datos mutables, y por lo tanto podemos modificar sus elementos: sustituir, agregar y quitar. Para sustituir un elemento de una lista basta con acceder al elemento correspondiente mediante indexación y asignar un nuevo valor, veamos el siguiente ejemplo:

frutas = ["Naranja","Fresa","Durazno"]
print(frutas)
frutas[0] = "Pera"
print(frutas)
['Naranja', 'Fresa', 'Durazno']
['Pera', 'Fresa', 'Durazno']

Como puedes ver, en la lista frutas hemos sustituido el elemento ubicado en el índice 0 ("Naranja") por un nuevo valor ("Pera").

Se pueden hacer múltiples sustituciones utilizando la notación de slicing, pero se debe tener cuidado que el tamaño de la porción que estamos tomando corresponda con el tamaño de la lista que estamos reasignando:

print(frutas)
frutas[0:2] = ["Piña","Kiwi"]
print(frutas)
['Pera', 'Fresa', 'Durazno']
['Piña', 'Kiwi', 'Durazno']

En este caso hemos sustituido a los elementos ubicados en los índices 0 y 1 ("Pera" y "Fresa") por los nuevos valores ("Piña" y "Kiwi") .

5.1.3. Agregar elementos a una lista#

Para agregar elementos a una lista podemos utilizar los métodos append e insert, naturalmente la elección está sujeta al comportamiento que muestran cada uno de estos métodos. El método append nos permite agregar elementos al final de la lista, en cambio insert nos permite insertar elementos en una posición específica de la lista.

Por ejemplo, en la lista frutas creada previamente podríamos ir agregando más elementos con append:

print(frutas)
frutas.append("Melón")
print(frutas)
['Piña', 'Kiwi', 'Durazno']
['Piña', 'Kiwi', 'Durazno', 'Melón']

Hay que tener en cuenta que el método append no permite agregar más de un elemento a la vez, si intentaramos agregar un conjunto de elementos observa lo que pasa:

frutas.append(["Manzana","Ciruela"])
print(frutas)
['Piña', 'Kiwi', 'Durazno', 'Melón', ['Manzana', 'Ciruela']]

Lo anterior nos agrega una lista en lugar de dos elementos strings. Si quisiéramos agregar múltiples elementos al final de una lista podemos hacer uso del método extend, el cual si nos permite añadir múltiples elementos:

frutas.extend(["Manzana","Ciruela"])
print(frutas)
['Piña', 'Kiwi', 'Durazno', 'Melón', ['Manzana', 'Ciruela'], 'Manzana', 'Ciruela']

Vamos a corregir nuestra lista frutas sustituyendo la sublista que habíamos insertado por un nuevo elemento:

frutas[4] = "Uva"
print(frutas)
['Piña', 'Kiwi', 'Durazno', 'Melón', 'Uva', 'Manzana', 'Ciruela']

Veamos ahora como funciona el método insert, debemos saber que la sintaxis de insert es como sigue:

lista.insert(k, elemento)

Donde k corresponde al índice en el cual quedará posicionado el nuevo elemento insertado, por ejemplo si en la lista frutas quisiéramos insertar "Sandía" en el índice 1 entonces haríamos lo siguiente:

frutas.insert(1, "Sandía")
print(frutas)
['Piña', 'Sandía', 'Kiwi', 'Durazno', 'Melón', 'Uva', 'Manzana', 'Ciruela']

Ejemplo. Evaluando funciones

Crea un programa que evalúe la función \( y = x^2 \) en \( x = [0,1,2,3,4,5] \). Todos los valores de \(x\) y los de la función evaluada \(y\) deberás almacenarlos en las listas X y Y.

Solución

Vamos a comenzar creando las listas vacias que almacenarán todos los valores:

X = []
Y = []

Ahora vamos a utilizar un ciclo for y la función range para iterar en el rango de 0 a 5, y dentro de ese ciclo for ir evaluando la función e ir agregando los valores calculados a las listas creadas previamente:

for x in range(0,6):
    y = x**2
    X.append(x)
    Y.append(y)

Bien, ahora podemos mostrar los valores contenidos en X y Y:

print(X)
print(Y)
[0, 1, 2, 3, 4, 5]
[0, 1, 4, 9, 16, 25]

5.1.4. Eliminar elementos de una lista#

Para eliminar elementos de una lista existente podemos hacer uso de los métodos remove, pop y clear, en lo subsiguiente describimos en qué situación podríamos utilizar cada uno de estos.

El método remove elimina el elemento de la lista pasado como argumento:

print(frutas)
frutas.remove("Uva")
print(frutas)
['Piña', 'Sandía', 'Kiwi', 'Durazno', 'Melón', 'Uva', 'Manzana', 'Ciruela']
['Piña', 'Sandía', 'Kiwi', 'Durazno', 'Melón', 'Manzana', 'Ciruela']

Es importante tomar en cuenta que el método remove elimina la primera aparición del elemento en una lista, si el elemento pasado como argumento está duplicado entonces aún quedará la segunda aparición, observa el siguiente ejemplo:

planetas = ["Mercurio","Venus","Tierra","Tierra","Marte"]
planetas.remove("Tierra")
print(planetas)
['Mercurio', 'Venus', 'Tierra', 'Marte']

Observa que eliminamos la primera aparición de "Tierra" pero no la segunda. Si el valor pasado al método remove no existe, Python devolverá un ValueError:

planetas.remove("Urano")
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[153], line 1
----> 1 planetas.remove("Urano")

ValueError: list.remove(x): x not in list

El método pop elimina el elemento de una lista cuyo índice ha sido pasado como argumento, sino se pasa un argumento se toma por defecto el índice -1, es decir el último elemento, tal como se muestra enseguida:

print(planetas)
planetas.pop()
print(planetas)
['Mercurio', 'Venus', 'Tierra', 'Marte']
['Mercurio', 'Venus', 'Tierra']

Observa que en la instrucción anterior se elimina el elemento ubicado en la última posición "Marte", dado que no hemos indicado de forma explícita un índice. Indicando, por ejemplo, el índice 1 podríamos eliminar al elemento ubicado en la segunda posición ("Venus"):

print(planetas)
planetas.pop(1)
print(planetas)
['Mercurio', 'Venus', 'Tierra']
['Mercurio', 'Tierra']

Toma en cuenta que si a pop le pasamos como argumento un índice fuera del rango válido de la lista entonces Python lanzará un IndexError:

planetas.pop(5)
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
Cell In[160], line 1
----> 1 planetas.pop(5)

IndexError: pop index out of range

El método clear nos permite limpiar completamente una lista, es decir: elimina todos sus elementos.

print(planetas)
planetas.clear()
print(planetas)
['Mercurio', 'Tierra']
[]

5.1.5. Buscar en una lista#

En algunas situaciones puede ser necesario buscar o identificar ciertos valores dentro de una lista, con la finalidad de determinar por ejemplo cuántas veces aparece un cierto elemento o identificar su posición para realizar alguna operación posterior con dicha información. El método count nos permite contar las apariciones de un cierto elemento dentro de una lista. Observemos el siguiente ejemplo en el cual determinamos cuántas veces aparece el número 5 en la lista puntos:

puntos = [10, 5, 3, 8, 10, 5, 6, 7, 9]
print( puntos.count(5) )
2

Tal como podemos observar, el método count nos dice cuántas veces aparece el elemento indicado, pero no nos dice nada acerca de dónde se ubica, para esto podemos hacer uso del método index, el cual nos permite identificar la posición de la primera aparición del elemento pasado como argumento.

puntos.index(5)
1

En Python disponemos también del operador in, con el cual podemos indentificar si un elemento (o una secuencia) está presente dentro de un objeto de tipo secuencia. Entonces, utilizando el operador in podríamos verificar si un elemento pertenece (o está contenido) a una lista utilizando la siguiente sintaxis:

elemento in lista

Esto nos devolverá siempre un booleano: True o False, dependiendo si elemento forma parte o no de lista. Veamos el ejemplo:

colores = ["Azul", "Verde", "Rojo", "Amarillo", "Morado", "Negro", "Blanco"]
print( "Blanco" in colores )
True
print( "Anaranjado" in colores )
False
colores.sort
['Azul', 'Verde', 'Rojo', 'Amarillo', 'Morado', 'Negro', 'Blanco']

5.1.6. Ordenar elementos de una lista#

El método sort nos permite ordenar una lista in-place, es decir, ordena los elementos y modifica la lista. Veamos un ejemplo:

numeros = [10,42,30,95,21]
numeros.sort()
print(numeros)
[10, 21, 30, 42, 95]

Observa que ahora la lista numeros contiene los mismos elementos que al principio, sólo que están ordenados en orden ascendente. Si queremos ordenar en orden descendente basta con utilizar el argumento reverse=True:

numeros.sort(reverse=True)
print(numeros)
[95, 42, 30, 21, 10]

Este método no solamente nos permite ordenar elementos númericos en una lista, sino también cualquier otro tipo de elemento. Veamos por ejemplo la siguiente lista que contiene cadenas de caracteres:

alumnos = ["Juan","Pedro","Ana","Antonio","Valeria"]
alumnos.sort()
print(alumnos)
['Ana', 'Antonio', 'Juan', 'Pedro', 'Valeria']

Notarás que en este caso al parecer la lista se ordena en orden alfabético, sin embargo, hay que tener precaución al respecto, observa lo siguiente:

alumnos = ["Juan","Pedro","Ana","Antonio","Valeria","alejandra","carlos"]
alumnos.sort()
print(alumnos)
['Ana', 'Antonio', 'Juan', 'Pedro', 'Valeria', 'alejandra', 'carlos']

Bueno, parece que hay algo más que un simple orden alfabético. En este caso la lista se ordena utilizando como referencia el código unicode asociado con cada caracter de las cadenas. Es bueno recordar en este punto que cada caracter representable en Python tiene asociado un código unicode, el cual podemos obtener utilizando la función ord:

ord("A"), ord("a")
(65, 97)

Observa que A y a tienen un código unicode distinto, es más, puedes observar que A tiene un código de menor valor que a, lo cual implica que si las ordenamos en orden ascendente (por default en el método sort) entonces A iría antes que a, incluso se puede verificar que cualquier letra mayúscula tiene un código unicode de menor valor que a, por ejemplo:

ord("V"), ord("P"), ord("Z")
(86, 80, 90)

Así pues, tiene sentido que tanto "alejandra" como "carlos" queden hasta final en la lista ordenada. Podemos ordenar la lista de manera alfabética sin importar si cada palabra comienza con mayúscula o minúscula, para esto debemos pasar una función adicional (str.lower) mediante el argumento key:

alumnos.sort(key=str.lower)
print(alumnos)
['alejandra', 'Ana', 'Antonio', 'carlos', 'Juan', 'Pedro', 'Valeria']

Con este argumento adicional (str.lower) todas las cadenas de la lista se convierten a minúsculas y luego se comparan.

Con el argumento key podemos utilizar tanto funciones built-in como definidas por el usuario, observa el siguiente ejemplo en donde utilizamos la función len:

alumnos.sort(key=len)
print(alumnos)
['Ana', 'Juan', 'Pedro', 'carlos', 'Valeria', 'Antonio', 'alejandra']

Observa que este caso las cadenas de la lista se ordenan de acuerdo a su longitud, en orden ascendente. Podemos también usar funciones definidas por nosotros, observa el siguiente ejemplo:

ultima_letra = lambda x: x[-1]
alumnos.sort(key=ultima_letra)
print(alumnos)
['Ana', 'Valeria', 'alejandra', 'Juan', 'Pedro', 'Antonio', 'carlos']

En este caso la función ultima_letra indica que vamos a ordenar utilizando el último caracter de la cadena como referencia.

5.1.7. Comprensión de listas (List Comprehension)#

La comprensión de listas (list comprehension) es una manera de crear listas a partir de una secuencia existente a la cual se le aplica una expresión. De manera general, la sintaxis más básica es:

lista = [expresión for elemento in secuencia]

Veamos el siguiente ejemplo, en el cual creamos la lista cuadrados a partir de la lista numeros, observa que cada elemento de numeros se eleva al cuadrado:

numeros = [1,3,5,7,9]
cuadrados = [k**2 for k in numeros]
cuadrados
[1, 9, 25, 49, 81]

Ahora veamos este otro ejemplo, en el cual generamos una lista que contiene el número de caracteres de cada cadena contenida en la lista alumnos:

alumnos = ["Ana","Ximena","Javier","Antonio"]
numero_de_vocales = [len(k) for k in alumnos]
numero_de_vocales
[3, 6, 6, 7]

En una lista por comprensión se pueden incluir también condiciones mediante la sentencia if. En el siguiente ejemplo podemos ver que en la lista aprobatorias únicamente se agregan las cantidades mayores o iguales a 70 contenidas en la lista calificaciones:

calificaciones = [55,68,91,88,72,39,75,83,28]
aprobatorias = [calif for calif in calificaciones if calif>=70]
print(aprobatorias)
[91, 88, 72, 75, 83]

También podemos incluir un condicional if-else mediante la siguiente sintaxis:

[expresión1 if condición else expresión2 for elemento in secuencia]

Donde típicamente condición es una operación de comparación que involucra a los elementos de secuencia. Observa el siguiente ejemplo:

aprobado_no_aprobado = ["A" if calif>=70 else "NA" for calif in calificaciones ]
print(aprobado_no_aprobado)
['NA', 'NA', 'A', 'A', 'A', 'NA', 'A', 'A', 'NA']

En el ejemplo anterior, a partir de la lista calificaciones generamos una nueva lista aprobado_no_aprobado que contiene "A" si el elemento correspondiente de calificaciones es mayor o igual a 70 y "NA" en otro caso.

También se pueden crear listas por comprensión anidadas, observemos el siguiente ejemplo:

grupo_1 = ["María","Ana","Ximena"]
grupo_2 = ["José","Juan","Carlos"]
parejas = [(p1, p2) for p1 in grupo_1 for p2 in grupo_2]
print(parejas)
[('María', 'José'), ('María', 'Juan'), ('María', 'Carlos'), ('Ana', 'José'), ('Ana', 'Juan'), ('Ana', 'Carlos'), ('Ximena', 'José'), ('Ximena', 'Juan'), ('Ximena', 'Carlos')]

Notarás que en este caso formamos una lista que contiene nueve tuplas de todas las posibles parejas que se pueden formar con las personas del grupo_1 y grupo_2. Obviamente, debemos considerar que la expresión de la cual se obtendrá cada elemento de la lista generada es dependiendo de lo que se requiera, por ejemplo, en lugar de tuplas pudimos haber concatenado las cadenas p1 y p2, resultando una cadena para cada elemento de la lista generada.

grupo_1 = ["María","Ana","Ximena"]
grupo_2 = ["José","Juan","Carlos"]
parejas = [p1+" y "+p2 for p1 in grupo_1 for p2 in grupo_2]
print(parejas)
['María y José', 'María y Juan', 'María y Carlos', 'Ana y José', 'Ana y Juan', 'Ana y Carlos', 'Ximena y José', 'Ximena y Juan', 'Ximena y Carlos']

La generación de listas por comprensión anidadas también se puede combinar con la sentencia if. Veamos el siguiente ejemplo, en el cual únicamente se “forman” las parejas siempre y cuando p1 comience con la letra "X". Obviamente en este caso únicamente tendremos parejas donde la primera integrante es "Ximena":

grupo_1 = ["María","Ana","Ximena"]
grupo_2 = ["José","Juan","Carlos"]
parejas = [p1+" y "+p2 for p1 in grupo_1 for p2 in grupo_2 if p1.startswith("X")]
print(parejas)
['Ximena y José', 'Ximena y Juan', 'Ximena y Carlos']

5.1.8. Copiar listas#

Antes de comenzar a explicar las maneras de copiar una lista, vamos a tratar de poner de manifiesto la importancia de tener precaución con esta situación. Vamos a crear una lista puntos_1 conformada por ciertos números:

puntos_1 = [10,20,30,40,50]

Y ahora vamos a crear otra lista puntos_2 asignándole directamente el contenido de puntos_1:

puntos_2 = puntos_1
print(puntos_1)
print(puntos_2)
[10, 20, 30, 40, 50]
[10, 20, 30, 40, 50]

Hasta acá nada raro, al parecer. Ahora vamos a modificar la lista puntos_1 agregándole un elemento con append:

puntos_1.append(60)
print(puntos_1)
print(puntos_2)
[10, 20, 30, 40, 50, 60]
[10, 20, 30, 40, 50, 60]

¡Ajá! La lista puntos_2 también sufrió modificaciones. El detalle está en que cuando hacemos lista_2 = lista_1 realmente no estamos haciendo una copia de lista_1 sino que estamos agregando una nueva etiqueta a un mismo objeto que ya está en memoria.

Un problema como el anterior se resuelve haciendo una copia superficial (shallow copy) de la lista. Una manera de hacerlo es utilizando el método copy que proporcionan las listas. Para ejemplificar, retomaremos el mismo ejemplo anterior:

puntos_1 = [10,20,30,40,50]
puntos_2 = puntos_1.copy()
print(puntos_1)
print(puntos_2)
[10, 20, 30, 40, 50]
[10, 20, 30, 40, 50]

Hemos generado puntos_2 a partir de puntos_1 mediante copy, veamos qué ocurre si modificamos a puntos_1:

puntos_1.append(60)
print(puntos_1)
print(puntos_2)
[10, 20, 30, 40, 50, 60]
[10, 20, 30, 40, 50]

Perfecto, ahora ya no tenemos el problema. Esto mismo se logra si utilizamos el operador de slicing [:]:

puntos_1 = [10,20,30,40,50]
puntos_2 = puntos_1[:]
puntos_1.append(60)
print(puntos_1)
print(puntos_2)
[10, 20, 30, 40, 50, 60]
[10, 20, 30, 40, 50]

O directamente la función list:

puntos_1 = [10,20,30,40,50]
puntos_2 = list(puntos_1)
puntos_1.append(60)
print(puntos_1)
print(puntos_2)
[10, 20, 30, 40, 50, 60]
[10, 20, 30, 40, 50]

Las copias superficiales funcionan bien siempre y cuando los elementos que contenga la lista sean inmutables, sin embargo, si la lista contiene objetos mutables (como otra lista, por ejemplo) entonces lo anterior ya no funciona. Veamos el siguiente ejemplo:

puntos_1 = [[10,20,30],[100,200,300]]
puntos_2 = puntos_1.copy()
print(puntos_1)
print(puntos_2)
puntos_1[0].append(40)
print("Después de la modificación:")
print(puntos_1)
print(puntos_2)
[[10, 20, 30], [100, 200, 300]]
[[10, 20, 30], [100, 200, 300]]
Después de la modificación:
[[10, 20, 30, 40], [100, 200, 300]]
[[10, 20, 30, 40], [100, 200, 300]]

Observa que la sublista en el índice 0 ha sufrido modificaciones tanto en puntos_1 como en puntos_2. Esto se puede resolver haciendo una copia profunda (deep copy) de la lista, para lo cual podemos hacer uso de la función deepcopy del módulo copy:

import copy
puntos_1 = [[10,20,30],[100,200,300]]
puntos_2 = copy.deepcopy(puntos_1)
print(puntos_1)
print(puntos_2)
puntos_1[0].append(40)
print("Después de la modificación:")
print(puntos_1)
print(puntos_2)
[[10, 20, 30], [100, 200, 300]]
[[10, 20, 30], [100, 200, 300]]
Después de la modificación:
[[10, 20, 30, 40], [100, 200, 300]]
[[10, 20, 30], [100, 200, 300]]

5.2. Tuplas (tuple)#

Las tuplas son secuencias de elementos similares a las listas, la diferencia principal es que las tuplas no pueden ser modificadas directamente, es decir, una tupla no dispone de los métodos como append o insert que modifican los elementos de una lista.

Para definir una tupla, los elementos se separan con comas y se encierran entre paréntesis.

colores=("Azul","Verde","Rojo","Amarillo","Blanco","Negro","Gris")

Las tuplas al ser secuencias pueden accederse mediante la notación de corchetes e índice.

colores[0]
'Azul'
colores[-1]
'Gris'
colores[3]
'Amarillo'

Si intentamos modificar alguno de los elementos de la tupla Python nos devolverá un TypeError:

colores[0] = "Café"
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[15], line 1
----> 1 colores[0] = "Café"

TypeError: 'tuple' object does not support item assignment
d = {(1,2): 200, (0,0): 500}
d.get((0,0))
500

5.3. Diccionarios (dict)#

Los diccionarios son estructuras que contienen una colección de elementos de la forma clave: valor separados por comas y encerrados entre llaves. Las claves deben ser objetos inmutables y los valores pueden ser de cualquier tipo. Necesariamente las claves deben ser únicas en cada diccionario, no así los valores.

Para crear un diccionario se puede utilizar la siguiente sintaxis:

diccionario = {clave1:valor1, clave2:valor2, ..., claveN:valorN}

Vamos a definir un diccionario llamado edades en el cual cada clave será un nombre y el valor una edad:

edades = {"Ana": 25, "David": 18, "Lucas": 35, "Ximena": 30, "Ale": 20}
edades
{'Ana': 25, 'David': 18, 'Lucas': 35, 'Ximena': 30, 'Ale': 20}

Otra manera de crear un diccionario es con la sintaxis:

diccionario = dict(clave1=valor1, clave2=valor2, ..., claveN=valorN)

Veamos como crear el mismo diccionario anterior utilizando esta forma:

edades_2 = dict(Ana=25, David=18, Lucas=35, Ximena=30, Ale=20)
edades_2
{'Ana': 25, 'David': 18, 'Lucas': 35, 'Ximena': 30, 'Ale': 20}

Las claves de un diccionario pueden ser cualquier objeto que sea inmutable, por ejemplo, podemos utilizar enteros (int) como claves:

notas = {1:[10,10,9], 2:[8,7,9], 3:[5,7,6], 4:[10,9,10], 5:[6,9,7]}
notas
{1: [10, 10, 9], 2: [8, 7, 9], 3: [5, 7, 6], 4: [10, 9, 10], 5: [6, 9, 7]}

O incluso tuplas:

puntos = {
    (0,0): 1.57,
    (0,1): 5.48,
    (1,0): 3.14,
    (1,1): 6.28
}
puntos
{(0, 0): 1.57, (0, 1): 5.48, (1, 0): 3.14, (1, 1): 6.28}

Sin embargo, si intentamos utilizar una lista como clave, entonces Python nos lanzará un TypeError, dado que las listas son un tipo de objeto mutable:

puntos = {
    [0,0]: 1.57,
    [0,1]: 5.48,
    [1,0]: 3.14,
    [1,1]: 6.28
}
puntos
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[75], line 1
----> 1 puntos = {
      2     [0,0]: 1.57,
      3     [0,1]: 5.48,
      4     [1,0]: 3.14,
      5     [1,1]: 6.28
      6 }
      7 puntos

TypeError: unhashable type: 'list'

Debemos tener cuidado con las claves repetidas al momento de crear un diccionario, puesto que cada clave debe ser única, entonces Python conserva el último valor asignado a una clave repetida, observa el siguiente ejemplo:

edades = {"Ana": 25, "David": 18, "Lucas": 35, "Ximena": 30, "Ale": 20, "Ana": 10}
edades
{'Ana': 10, 'David': 18, 'Lucas': 35, 'Ximena': 30, 'Ale': 20}

5.3.1. Acceder a los elementos de un diccionario#

Podemos acceder a cada valor de un diccionario utilizando corchetes y su clave, por ejemplo, si quisiéramos obtener la edad de la clave Lucas se tendría que escribir:

edades["Lucas"]
35

Algo similar podríamos hacer utilizando el método get:

edades.get("Lucas")
35

La diferencia entre la notación de corchetes y el método get radica en la manera en que se manejan las claves inexistentes. Si utilizamos la notación de corchetes e intentamos acceder a un elemento cuya clave no existe, entonces Python nos devuelve un KeyError:

edades["Juan"]
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
Cell In[88], line 1
----> 1 edades["Juan"]

KeyError: 'Juan'

Cuando utilizamos get, Python nos devuelve un None en el caso de que no se encuentre la clave.

print( edades.get("Juan") )
None

Sin embargo, es posible indicar explícitamente, mediante un segundo argumento, el valor que debe devolver get cuando no se encuentre la clave:

edades.get("Juan", 0)
0

En este caso, dado que "Juan" no es una clave de edades, entonces el método get devuelve el valor 0.

El método items permite obtener un conjunto de tuplas (dict_items) de la forma (clave, valor) que podemos recorrer utilizando, por ejemplo, un ciclo for:

for nombre,edad in edades.items():
    print(f"{nombre} tiene {edad} años")
Ana tiene 10 años
David tiene 18 años
Lucas tiene 35 años
Ximena tiene 30 años
Ale tiene 20 años

El método keys nos devuelve una lista de todas las claves del diccionario:

edades.keys()
dict_keys(['Ana', 'David', 'Lucas', 'Ximena', 'Ale'])

De manera similar, values nos devuelve una lista de todos los valores en el diccionario:

edades.values()
dict_values([10, 18, 35, 30, 20])

Cuando tenemos un diccionario que anida otros diccionarios u otras estructuras de datos, es importante tener en cuenta que podemos encadenar la notación de corchetes e índices/claves. Para ejemplificar, vamos a trabajar con el siguiente diccionario, que almacena información acerca de alumnos, cada clave del diccionario es la matrícula de un alumno, y el valor asociado con dicha clave es otro diccionario cuyas claves son "Nombre", "Apellidos" y "Calificaciones". En la clave "Calificaciones" se almacena otro diccionario que contiene asignaturas como claves y sus calificaciones correspondientes como valor.

alumnos = {
    "25001": {
        "Nombre": "Juan",
        "Apellidos": "Pérez López",
        "Calificaciones": {
            "Química": 10,
            "Física": 8.5,
            "Matemáticas": 9
        }
    },
    "25002": {
        "Nombre": "Ana",
        "Apellidos": "Ramírez García",
        "Calificaciones": {
            "Química": 9,
            "Física": 10,
            "Matemáticas": 9
        }
    },
    "25003": {
        "Nombre": "Juan",
        "Apellidos": "Vázquez González",
        "Calificaciones": {
            "Química": 7.5,
            "Física": 9,
            "Matemáticas": 9.5
        }
    }
}

Vamos a suponer que queremos acceder al nombre de un alumno en específico, al "25002" por ejemplo, para esto haríamos lo siguiente:

alumnos["25002"]["Nombre"]
'Ana'

Para acceder a la calificación de Química de este mismo alumno, tendríamos que encadenar otro corchete e índice para indicar que del diccionario contenido en la clave "Calificaciones" nos interesa el valor asociado con la clave "Química":

alumnos["25002"]["Calificaciones"]["Química"]
9

5.3.2. Agregar elementos a un diccionario#

Podemos agregar elementos a un diccionario de varias maneras, una de ellas es utilizando la notación de corchetes, mediante la sintaxis:

diccionario["clave_nueva"] = valor_nuevo

Para ejemplificar vamos a definir el siguiente diccionario que contiene algunos países de Latinoamérica como claves y sus poblaciones como valor:

latinoamerica = {
    "Brasil": 203_062_512,
    "México": 131_135_337,
    "Colombia": 52_939_527,
    "Argentina": 46_621_847
}

Para agregar un quinto país podríamos hacer lo siguiente:

latinoamerica["Perú"] = 32_440_172
print(latinoamerica)
{'Brasil': 203062512, 'México': 131135337, 'Colombia': 52939527, 'Argentina': 46621847, 'Perú': 32440172}

Es posible también utilizar el método update para agregar uno o más elementos a un diccionario, por ejemplo:

latinoamerica.update({"Venezuela": 30_518_260, "Chile":18_549_457})
print(latinoamerica)
{'Brasil': 203062512, 'México': 131135337, 'Colombia': 52939527, 'Argentina': 46621847, 'Perú': 32440172, 'Venezuela': 30518260, 'Chile': 18549457}

Otra manera de agregar elementos a un diccionario existente es utilizando el operador |, el cual nos permite unir dos diccionarios. Veamos el siguiente ejemplo, primero definimos un diccionario denominado europa que contiene algunos países como claves y sus poblaciones como valor:

europa = {
    "Alemania": 83_871_923,
    "Reino Unido": 69_506_575,
    "Francia": 66_638_431,
}

Para agregar más países con el operador | haremos lo siguiente:

europa = europa | {"Italia": 61_208_911, "España": 48_085_361}
print(europa)
{'Alemania': 83871923, 'Reino Unido': 69506575, 'Francia': 66638431, 'Italia': 61208911, 'España': 48085361, 'Polonia': 37897185}

Es posible utilizar la versión corta de la expresión anterior utilizando el operador |=:

europa |= {"Polonia": 37_897_185}
print(europa)
{'Alemania': 83871923, 'Reino Unido': 69506575, 'Francia': 66638431, 'Italia': 61208911, 'España': 48085361, 'Polonia': 37897185}

5.3.3. Actualizar elementos de un diccionario#

Prácticamente cualquiera de las maneras anteriores de agregar elementos nos sirven también para actualizar valores, simplemente haciendo uso de claves que ya existen y en consecuencia se actualizarán con los nuevos valores. Por ejemplo, si quisiéramos actualizar la población de Francia en el diccionario europa que creamos previamente, una posible manera de hacerlo sería:

europa["Francia"] = 66_650_000
print(europa)
{'Alemania': 83872000, 'Reino Unido': 69506575, 'Francia': 66650000, 'Italia': 61208911, 'España': 48090000, 'Polonia': 37898000}

Para actualizar múltiples elementos podríamos utilizar el método update, por ejemplo, vamos a actualizar las poblaciones de Alemania, España y Polonia:

europa.update({"Alemania":83_872_000, "España":48_090_000, "Polonia":37_898_000})
print(europa)
{'Alemania': 83872000, 'Reino Unido': 69506575, 'Francia': 66650000, 'Italia': 61208911, 'España': 48090000, 'Polonia': 37898000}

5.3.4. Eliminar elementos de un diccionario#

Para eliminar elementos de un diccionario podemos hacer uso del método pop, el cual recibe como argumento la clave del elemento que queremos borrar y nos devuelve el valor asociado con dicha clave. Veamos un ejemplo:

latinoamerica = {
    "Brasil": 203_062_512,
    "México": 131_135_337,
    "Colombia": 52_939_527,
    "Argentina": 46_621_847,
    "Perú": 32_440_172,
    "Venezuela": 30_518_260, 
    "Chile":18_549_457,
}

colombia_poblacion = latinoamerica.pop("Venezuela")
print(colombia_poblacion)
print(latinoamerica)
30518260
{'Brasil': 203062512, 'México': 131135337, 'Colombia': 52939527, 'Argentina': 46621847, 'Perú': 32440172, 'Chile': 18549457}

Observemos que en colombia_poblacion guardamos el valor que devuelve el método pop y si mostramos el diccionario actualizado notaremos que ya no existe el elemento con la clave "Venezuela".

Otra manera de eliminar elementos de un diccionario es utilizando el método popitem, el cual elimina el último elemento del diccionario y lo devuelve en la forma de una tupla de dos elementos (clave, valor). Veamos un ejemplo:

latinoamerica.popitem()
('Chile', 18549457)
print(latinoamerica)
{'Brasil': 203062512, 'México': 131135337, 'Colombia': 52939527, 'Argentina': 46621847, 'Perú': 32440172}

Otra manera de eliminar elementos específicos en un diccionario es utilizando la sentencia del seguida de la notación corchete y clave. Por ejemplo, si del diccionario latinoamerica quisiéramos borrar el elemento con la clave "Brasil" entonces haríamos lo siguiente:

del latinoamerica["Brasil"]
print(latinoamerica)
{'México': 131135337, 'Colombia': 52939527, 'Argentina': 46621847, 'Perú': 32440172}

5.4. Ejercicios#


Escribe un programa que dada una lista de números enteros, devuelva un diccionario con los números clasificados en pares e impares. Por ejemplo, si la lista de entrada es:

numeros = [11, 15, 30, 45, 38, 36, 88, 95, 127, 21]

Deberá devolver:

{'Pares': [30, 38, 36, 88], 'Impares': [11, 15, 45, 95, 127, 21]}

Desarrolla un programa que dada una lista de números, calcule y devuelva una lista con la diferencia entre los elementos adyacentes de la lista, es decir, sea \(X\) una lista cuyos elementos son:

\[ X = \left[x_1,\, x_2,\, x_3,\, \cdots,\, x_n\right] \]

La lista resultante de las diferencias entre elementos adyacentes está dada por:

\[ X_d = \left[x_2-x_1,\, x_3 - x_2, \,\cdots, \,x_n - x_{n-1} \right] \]

Nota que \(X_d\) tendrá un elemento menos que la lista original \(X\).


Desarrolla un programa que evalúe numéricamente la función \(f(x)=x + 3\) en los valores para \(x\) que el usuario le proporcione mediante una lista. El programa deberá devolver una lista de tuplas de la forma [(x1, f(x1)), (x2, f(x2)), ..., (xn, f(xn))], donde los términos f(xi) son los que resultan de evaluar \(f(x)\) en \(x_i\). Por ejemplo, si la lista proporcionada es:

[10, 15, 50, 95, 110]

Entonces el programa deberá devolver:

[(10, 13), (15, 18), (50, 53), (95, 98), (110, 113)]

Escribe un programa que dados:

  • Un límite inferior a

  • Un límite superior b

  • Una cantidad de elementos n

Devuelva una lista con n elementos linealmente equiespaciados entre a y b, incluidos estos. Por ejemplo:

  • Si a=0, b=10 y n=11, entonces devuelve: [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0]

  • Si a=100, b=500 y n=6, entonces devuelve: [100.0, 180.0, 260.0, 340.0, 420.0, 500.0]

  • Si a=1.5, b=4.5 y n=4, entonces devuelve: [1.5, 2.5, 3.5, 4.5]


Escriba un programa que reciba dos listas de números, con la misma cantidad de elementos, y que deberá devolver una lista que contenga la suma elemento a elemento de las listas. Por ejemplo, sean \(X\) y \(Y\) listas dadas por:

\[ X = \left[ x_1, \, x_2, \, \cdots ,\, x_n \right] \]
\[ Y = \left[ y_1, \, y_2, \, \cdots ,\, y_n \right] \]

Entonces la lista resultante deberá ser:

\[ R = [x_1 + y_1, \, x_2 + y_2, \, \cdots, \, x_n + y_n] \]

Desarrolle un programa que permita ordenar una lista de números de acuerdo con la suma de sus dígitos. Por ejemplo, dada la lista:

[100, 235, 305, 178, 700, 11, 45]

Entonces la lista ordenada deberá ser:

[100, 11, 700, 305, 45, 235, 178]

Escribe un programa que, dado el siguiente diccionario con algunos materiales y sus propiedades mecánicas:

materiales = {
    "Acero 1018": {"E": 205e9, "nu": 0.29, "Sy": 370e6, "Sut": 440e6},
    "Acero 1045": {"E": 200e9, "nu": 0.29, "Sy": 450e6, "Sut": 585e6},
    "Acero 4140": {"E": 210e9, "nu": 0.27, "Sy": 415e6, "Sut": 655e6},
    "Aluminio 6061": {"E": 69e9, "nu": 0.33, "Sy": 276e6, "Sut": 310e6},
}

Devuelva una tabla como la siguiente:

|      Material      |    E     |    nu    |    Sy    |   Sut    |
------------------------------------------------------------------
|     Acero 1018     |  205.0   |   0.29   |  370.0   |  440.0   |
|     Acero 1045     |  200.0   |   0.29   |  450.0   |  585.0   |
|     Acero 4140     |  210.0   |   0.27   |  415.0   |  655.0   |
|   Aluminio 6061    |   69.0   |   0.33   |  276.0   |  310.0   |