Listas
1 Introducción
Una lista es una estructura de datos que contiene una secuencia de elementos.
2 Listas
Las listas en Pyton son una secuencia de elementos, heterogéneos y mutables, separados por comas y encerrados entre corchetes [ ].
Las listas son estructuras mutables porque además de permitir el acceso a los elementos, estos pueden modificarse, suprimirse o agregarse nuevos.
Para crear una variable de tipo lista basta con asignar una secuencia de elementos separados por comas entre corchetes.
<variable> = [<lista de elementos>]
Las listas también se pueden crear usando la función list() a partir de una secuencia, una colección o un iterador. Crea una lista cuyos elementos son los mismos y están en el mismo orden que los elementos del iterable.
>>> lista = list('Hola') >>> lista ['H', 'o', 'l', 'a']
Para definir una lista vacía, a la que con posterioridad se podría agregar elementos, basta con asignarle dos corchetes sin contenido:
lista = []
Las listas son objetos muy versátiles, que pueden contener elementos de diferentes tipos, aunque en muchos casos todos son del mismo tipo.
>>> numeros = [1, 2, 3, 4, 5] >>> cadenas = ['Hola', 'Mundo', 'Python'] >>> combinado = ['Hola', 2020, [2020, 1, 20]]
2.1 Acceso a elementos de una lista
Una lista en Python es una estructura de datos formada por una secuencia ordenada de objetos. Esto permite acceder a los elementos de la lista independientemente mediante el uso de un índice encerrado entre corchetes [ ].
Los índices de las listas funcionan de la misma manera que los índices de las cadenas.
Python usa indexación basada en cero. Si el índice está fuera de los límites de la cadena, se generará un error.
Los índices deben ser valores enteros, el uso de decimales provocará un error.
El uso de índices negativos nos permite recorrer las listas en sentido inverso. El último elemento viene referenciado por el índice -1.
>>> lista = ['Hola', 'Mundo', 'Python'] >>> m = lista[1] >>> m 'Mundo' >>> p = lista[-1] >>> p 'Python'
A continuación podemos ver una representación de la lista con sus índices positivos y negativos.

Índices positivos y negativos
Es posible utilizar más de un índice para acceder al contenido de los elementos.
>>> n = lista[1][2] >>> n 'n'
A través de los índices, pueden cambiarse los elementos de una lista.
>>> lista[0] = 'Hi' >>> lista ['Hi', 'Mundo', 'Python']
Como las listas son mutables debemos tener cuidado al copiar listas.
>>> lista1 = ['Hola', 'Mundo', 'Python'] >>> lista2 = lista1 >>> lista1 ['Hola', 'Mundo', 'Python'] >>> lista2 ['Hola', 'Mundo', 'Python'] >>> lista1[0] = 'Hi' >>> lista1 ['Hi', 'Mundo', 'Python'] >>> lista2 ['Hi', 'Mundo', 'Python']
Podemos ver que el contenido de ambas listas son iguales, ya que basta cambiar una de ellas para ver que cambian las dos. Cuando copiamos una variable en realidad estamos haciendo otra referencia al mismo objeto, estamos haciendo lo que se denomina copia superficial. Cuando cambiamos un elemento de la lista original, cosa que podemos hacer porque las listas son mutables, al no haber creado ningún objeto nuevo, las dos variables siguen apuntando a la misma ubicación de memoria, y ambas tiene el elemento modificado.
La solución pasa por crear un nuevo objeto de tipo lista, haciendo de esta forma una copia profunda. El operador [:] es una forma de crear una nueva lista.
<nueva_lista> = <lista_original>[:]
De esta forma, siguiendo con el ejemplo anterior:
>>> lista1 = ['Hola', 'Mundo', 'Python'] >>> lista2 = lista1[:] # copiamos creando un nuevo objeto de tipo lista >>> lista1[0] = 'Hi' >>> lista1 ['Hi', 'Mundo', 'Python'] >>> lista2 ['Hola', 'Mundo', 'Python']
Internamente Python mantiene la cuenta de cuántas referencias hay a cada objeto. Cuando la cantidad de referencias de un objeto llega a 0, el objeto ya no es necesario, y la memoria que había estado utilizando se libera. Es lo que se conoce como recolección de basura (garbage collection).
2.1.1 Desempaquetado
Podemos acceder a los elementos de una lista vía variables independientes.
El desempaquetado (unpacking) de listas requiere que la cantidad de variables, separadas por comas, a la izquierda del signo igual coincida con el tamaño de la secuencia.
<variables> = <lista>
Así podemos desempaquetas las listas de la forma.
>>> lista = ['Hola', 'Mundo', 'Python'] >>> h, m, p = lista >>> print(h, m, p) Hola Mundo Python
El operador de desempaquetado ( * ) amplía la funcionalidad de desempaquetado para permitirnos recoger o empaquetar múltiples valores en una única variable. Independientemente de si conocemos o no el número de elementos.
Podemos formar una expresión utilizando el operador de desempaquetado junto con una variable. El resto de las variables son variables obligatorias que deben rellenarse con valores concretos.
>>> primero, *resto, ultimo = [1, 2, 3, 4, 5] >>> print(primero, resto, ultimo) 1 [2, 3, 4] 5 >>> primero, segundo, *resto = [1, 2, 3, 4, 5] >>> print(primero, segundo, resto) 1 2 [3, 4, 5] >>> *resto, penultimo, ultimo = [1, 2, 3, 4, 5] >>> print(resto, penultimo, ultimo) [1, 2, 3] 4 5
Si no hay suficientes valores siempre se desempaquetarán los correspondientes a las variables obligatorias, mientras que la variable de desempaquetado quedaría vacía.
>>> primero, *resto, ultimo = [1, 2] >>> print(primero, resto, ultimo) 1 [] 2
Por supuesto, si no hay suficientes valores para las variables obligatorias recibiremos un error.
>>> primero, *resto, ultimo = [1] Traceback (most recent call last): . . . ValueError: not enough values to unpack (expected at least 2, got 1)
Empaquetar valores en una variable con el operador * puede ser útil cuando necesitamos recoger los elementos de un generador en una única variable sin utilizar la función list().
Si desempaquetamos en una única variable varios valores debemos añadir una coma a la variable.
>>> *r, = range(10) >>> r [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Otra funcionalidad que ofrece el operador de desempaquetado es la capacidad de fusionar varios iterables en una única secuencia. Esta funcionalidad podemos utilizarla con listas, tuplas y conjuntos.
>>> a = [1, 2, 3] >>> b = [7, 8, 9] >>> c = [*a, 4, 5, 6, *b] >>> c [1, 2, 3, 4, 5, 6, 7, 8, 9]
De esta forma podemos crear secuencias uniendo otras secuencias existentes sin hacer uso de ninguna función.
2.1.2 Cortes de listas
La forma para obtener subsecciones o cortes (slice) de una lista es mediante una ampliación del operador de índices.
<lista>[<start>:<end>]
donde
- start marca el índice de comienzo de los elementos.
- end indica hasta qué elemento se extiende el segmento de la lista, pero sin incluirlo.
Si omitimos el primer índice (start), la sublista comienza al principio de la lista.
Si se omite el segundo índice (end), llegaremos hasta el final de la lista.
Si el primer índice es mayor o igual que el segundo, el resultado es una lista vacía, representado por dos corchetes.
Si se omiten los dos índices, manteniendo los dos puntos, se copia toda la lista.
>>> lista = ['Hola', 'Mundo', 'Python'] >>> print(lista[1:3]) ['Mundo', 'Python']
El operador de índices posee un tercer elemento
<lista>[<start>:<end>:<step>]
Donde
- step especifica el incremento para el índice.
Si no se especifica el paso el valor del incremento es 1.
>>> print(lista[0:3:2]) ['Hola', 'Python']
Los cortes nos facilitan realizar operaciones sobre las listas, como borrados selectivos.
>>> lista = [100, 200, 300, 400, 500] >>> lista[1::2] [200, 400] >>> del lista[1::2] >>> lista [100, 300, 500]
2.2 Recorrer una lista
El proceso para recorrer una lista, elemento a elemento, puede realizarse con cualquiera de los bucles de que dispone Python.
2.2.1 Bucle for
El bucle for nos permite recorrer todos los elementos de una lista.
>>> lista = ['Hola', 'Mundo', 'Python'] >>> for elemento in lista: ... print(elemento) Hola Mundo Python
Si precisamos tanto el índice como el elemento, disponemos de la función enumerate().
>>> for i, e in enumerate(lista): ... print(i, e) 0 Hola 1 Mundo 2 Python
2.3 Operadores y funciones de listas
Las listas disponen de las operaciones y funciones incorporadas siguientes:
Operador | Descripción |
---|---|
+ | Concatenación - Une dos o más listas en una sola. |
* | Repetición - Crea una nueva lista concatenando múltiples copias de la misma lista. |
[ ] | Índice - Proporciona el elemento del índice dado. |
[ : ] | Corte (slice) - Devuelve una secuencia de elementos según el rango indicado. |
in | Pertenencia - Devuelve True si el carácter existe en la lista dada. |
not in | Pertenencia - Devuelve True si el carácter NO existe en la lista dada. |
cmp(lista1, lista2) | Compara los elementos de ambas listas.
Devuelve:
|
len(lista) | Devuelve la longitud de la lista. El número de elementos de la lista. |
list(secuencia) | Devuelve una lista con los elementos de la secuencia dada. |
max(lista) | Devuelve el elemento mayor de la lista. |
min(lista) | Devuelve el elemento menor de la lista. |
sorted(lista) | Devuelve una nueva lista ordenada. |
Veamos unos ejemplos.
>>> saludo = ['Hola', 'Python'] >>> greeting = ['Hi', 'Python'] >>> # Concatenación >>> print(saludo + greeting) ['Hola', 'Python', 'Hi', 'Python'] >>> # Repetición >>> print(saludo * 3) ['Hola', 'Python', 'Hola', 'Python', 'Hola', 'Python'] >>> # Pertenencia >>> if 'Hola' in saludo: ... print(True) True >>> if 'Hi' not in saludo: ... print(True) True
2.4 Métodos de listas
Python dispone de un conjunto de métodos para su uso con las listas.
Como las listas son mutables, todos los métodos actúan directamente sobre los elementos de las listas.
Método | Descripción |
---|---|
list.append(elem) | Añade el elemento elem al final de la lista.
No devuelve una nueva lista, sólo modifica la original. |
list.clear() | Elimina todos los elementos de la lista. |
list.count(elem) | Devuelve el número de veces que el elemento elem aparece en la lista. |
list.extend(list2) | Añade los elementos de list2 al final de la lista.
El uso del operador de concatenación + o += en una lista es similar al uso de extend(). |
list.index(elem) | Busca la primera instancia del elemento elem desde el principio de la lista y devuelve su índice.
Lanza un ValueError si el elemento no aparece. El operador de pertenencia in verifica sin lanzar ValueError. |
list.insert(index, elem) | Inserta el elemento en el índice index, desplazando los siguientes elementos a la derecha. |
list.pop(index) | Elimina y devuelve el elemento en la posición indicada por el índice index.
Devuelve el elemento más a la derecha (el último de la lista) si se omite el índice. |
list.remove(elem) | Busca la primera instancia del elemento elem y la elimina.
Lanza un ValueError si el elemento no existe. |
list.reverse() | Invierte la lista en si misma (NO devuelve una nueva lista). |
list.sort() | Ordena la lista. (NO devuelve una nueva lista). |
Las listas no controlan si se insertan elementos repetidos.
La eliminación de elementos en una lista nunca deja huecos, lo que tenemos en la lista es lo que hay en la lista en ese momento.
No confundir la función sorted() con el método sort(). La función devuelve una lista ordenada, mientras que el método nos ordena la lista internamente.
Veamos unos ejemplos.
>>> saludo = ['Hola', 'Python'] >>> greeting = ['Hi', 'Python'] >>> saludo.append('Mundo') >>> saludo.insert(0, 'Hello') >>> saludo.extend(greeting) >>> # ningún método devuelve una nueva lista >>> print(len(saludo), saludo) 6 ['Hello', 'Hola', 'Python', 'Mundo', 'Hi', 'Python'] >>> # índice de la primera aparición del elemento >>> print(saludo.index('Python')) 2 >>> saludo.remove('Hi') >>> print(saludo.pop(1)) 'Hola' >>> print(saludo) ['Hello', 'Python', 'Mundo', 'Python'] >>> print(saludo.count('Python')) 2 >>> saludo.sort() >>> print(saludo) ['Hello', 'Mundo', 'Python', 'Python'] >>> saludo.reverse() >>> print(saludo) ['Python', 'Python', 'Mundo', 'Hello']
Para eliminar elementos duplicados en una lista disponemos de un truco que hace uso de una estructura que veremos más adelante, el conjunto (set). Como los conjuntos no admiten elementos repetidos, convertiremos la lista en un conjunto con el método set() y el resultado en una nueva lista, ya sin duplicados.
>>> caminante = 'caminante no hay camino se hace camino al andar' >>> lista = caminante.split() >>> lista ['caminante', 'no', 'hay', 'camino', 'se', 'hace', 'camino', 'al', 'andar'] >>> nueva = list(set(lista)) >>> nueva # ya tiene solo un 'camino' ['hace', 'se', 'camino', 'no', 'andar', 'hay', 'caminante', 'al']
Es posible utilizar las listas para implementar otras estructuras de datos, como pilas y colas.
>>> elemento = 'Python' >>> ### pila >>> stack = ['Hola', 'Mundo'] >>> stack.append(elemento) # push. añade al extremo >>> print(stack) ['Hola', 'Mundo', 'Python'] >>> elemento = stack.pop() # pop. elimina del extremo >>> print(stack) ['Hola', 'Mundo'] >>> ### cola >>> queue = ['Hola', 'Mundo'] >>> queue.append(elemento) # push. añade al extremo >>> print(queue) ['Hola', 'Mundo', 'Python'] >>> elemento = queue.pop(0) # pop. elimina de la cabeza >>> print(queue) ['Mundo', 'Python']
Esta solución funciona bien para estructuras pequeñas, de unos cientos de elementos.
2.5 Comprensión de listas
Python soporta la creación de listas mediante expresiones denominadas comprensiones de listas. (El nombre proviene del lenguaje de programación Haskell). La comprensión de las listas proporciona una forma concisa de crearlas al establecer un patrón basado en el tratamiento de elementos de una lista anterior o de un objeto iterable.
Una comprensión de listas tiene la siguiente sintaxis:
<lista> = [<expresión> for <elemento> in <iterable> <filtro>]
La comprensión empieza y termina con corchetes [ ], para recordarnos que se va a generar una lista.
Sigue una expresión basada en la variable utilizada para cada elemento de la lista.
A continuación un bucle formado por la palabra reservada for seguida del nombre de la variable a utilizar, seguida de la palabra reservada in y el objeto del que vayamos a sacar los elementos, que debe ser un iterable.
El filtro es opcional y está formado por una expresión condicional if.
Las expresiones pueden ser cualquier cosa que pueda interpretar Python, lo que permite poner todo tipo de objetos en las listas.
El resultado será una nueva lista resultante de la evaluación de la expresión en el contexto de las cláusulas for e if que la siguen.
La comprensión de listas siempre devuelve una lista de resultados.
>>> # lista de los primeros números pares inferiores a 10 >>> pares = [i for i in range(10) if i % 2 == 0] >>> pares [0, 2, 4, 6, 8]
Que equivale, de una forma más extendida, a:
>>> pares = [] >>> for i in range(10): ... if i % 2 == 0: ... pares.append(i)
Lo que no es tan compacto y, además, nos obliga a inicializar la lista de destino.
Podemos emplear cualquier expresión.
>>> # lista de iniciales >>> lista = ['Hola', 'Mundo', 'Phyton'] >>> iniciales = [item[0] for item in lista] >>> iniciales ['H', 'M', 'P']
Las comprensiones de listas proporcionan una forma concisa y elegante de escribir código en Python. Suele ser una buena solución, ya que tenemos todo el código que necesitamos a la vista. Pero también puede ser un problema si la lógica no es sencilla. Un código demasiado compacto obliga a realizar un esfuerzo por entender su significado, sobre todo si hay comprensiones anidadas.
>>> lista = [i*2 for i in [j+1 for j in range(5)]] >>> lista [2, 4, 6, 8, 10]
Quizás en dos pasos es más sencillo de entender (y este ejemplo no es de los más complicados).
>>> serie = [j+1 for j in range(5)] >>> serie [1, 2, 3, 4, 5] >>> lista = [i*2 for i in serie] >>> lista [2, 4, 6, 8, 10]
Resumiendo, las comprensiones son una gran idea para escribir código con una lógica sencilla de una manera concisa y legible. Aunque, cuando la lógica es más compleja, si la unimos al uso de la generación por comprensión, el resultado puede llegar a ser incomprensible (aunque funcione).
2.6 Listas multidimensionales
Una lista es lo que en matemáticas se conoce como un vector, una matriz unidimensional.
Si creamos listas de listas podremos tener matrices multidimensionales.
matriz = [[1, 2, 3], [4, 5, 6], [7, 8,9]] # Matriz cuadrada de 3x3
Si la imprimimos fila a fila se parecerá más a la representación habitual de una matriz.
>>> for fila in matriz: ... print(fila) [1, 2, 3] [4, 5, 6] [7, 8, 9]
Al ser una matriz bidimensional necesitamos un bucle anidado para tratar los elementos individualmente.
>>> for fila in matriz: ... for elemento in fila: ... print(elemento, end=' ') ... print() 1 2 3 4 5 6 7 8 9
Y, empleando índices, que es otra posibilidad.
>>> for i in range(len(matriz)): ... for j in range(len(matriz[i])): ... print(matriz[i][j], end=' ') ... print() 1 2 3 4 5 6 7 8 9
La creación de listas por comprensión puede ser todo lo compleja que queramos, pero la creación de matrices multidimensionales vía comprensión se nos puede complicar un poco más según aumentemos de dimensiones. Pero todo es posible.
Una matriz de 7x5:
>>> matriz = [[x*y for y in range(5)] for x in range(7)] >>> for fila in matriz: ... print(fila) [0, 0, 0, 0, 0] [0, 1, 2, 3, 4] [0, 2, 4, 6, 8] [0, 3, 6, 9, 12] [0, 4, 8, 12, 16] [0, 5, 10, 15, 20] [0, 6, 12, 18, 24]
Y, rizando el rizo, también podemos tener matrices irregulares.
>>> matriz_irregular = [[1, 2, 3, 4, 5], [11, 22, 33], [111, 222, 333, 444], [1111]] >>> for fila in matriz_irregular: ... for elemento in fila: ... print(elemento, end=' ') ... print() 1 2 3 4 5 11 22 33 111 222 333 444 1111
2.7 Aplanar listas
Aplanar (flatten) una lista de listas o matriz bidimensional, es el procedimiento para eliminar una dimensión de la lista, y obtener una lista unidimensional con todos los elementos en secuencia.
Para eliminar la segunda dimensión de una lista de este tipo, podemos utilizar una comprensión de listas.
>>> matriz = [[1, 2, 3], [4, 5], [6, 7]] >>> lista = [item for sublist in matriz for item in sublist] >>> lista [1, 2, 3, 4, 5, 6, 7]
Otra forma, menos estilo Python, es hacer uso de un bucle anidado para recorrer todas las sublistas.
>>> lista = [] >>> for sublist in matriz: ... for item in sublist: ... lista.append(item) >>> lista [1, 2, 3, 4, 5, 6, 7]