Listas

Una lista es una colección ordenada de elementos, similar a una matriz unidimensional.

>>> lista = [1, 2, 3]
>>> lista
[1, 2, 3]
../_images/python_list.png

Las listas tienen un sistema de índices equivalente al que vimos para las cadenas de texto:

>>> lista[0]
1
>>> lista[2]
3
>>> lista[-1]
3
>>> lista[:2]
[1, 2]
>>> lista[:2] + [3, 4]
[1, 2, 3, 4]

También de forma análoga al caso de las cadenas de texto, todas estas operaciones devuelven una nueva lista o un elemento que podemos guardar en una variable:

>>> nueva_lista = lista[1:]
>>> nueva_lista
[2, 3]

Si a la lista le pedimos un rango devolverá una nueva lista, mientras que si lo que le pedimos es un sólo elemento devolverá un solo elemento, no una lista con un elemento.

>>> lista[:1]
[1]
>>> lista[0]
1

En este comportamiento las listas se diferencian ligeramente de las cadenas de texto. Mientras las cadenas de texto siempre devuelven cadenas de texto, ya estén compuestas éstas por uno o varios caracteres, las listas pueden devolver elementos individuales o pequeñas listas. En el ejemplo anterior cuando pedimos un rango (slice) ([:1]) se nos devuelve una lista con un elemento dentro ([1]), mientras que cuando pedimos un sólo elemento ([1]) se nos devuelve un elemento (1).

Podemos conocer la longitud de una lista utilizando la función len:

>>> len(lista)
4

En Python hay varios clases de objetos que pueden ser tratados de este modo, como: str (cadenas de texto), unicode (cadenas de texto con codificación), list (listas), tuple (listas inmutables) y arrays. De estos tipos de datos se dice que son secuencias, porque son en realidad secuencias ordenadas.

Dentro de las listas podemos guardar cualquier clase de elemento.

>>> lista_heterogenea = ['Monty', 3.14, 1]

También podríamos guardar otras listas en cada una de las posiciones de la lista. En este caso habríamos definido una matriz bidimensional:

>>> matriz = [['00', '01', '02'], ['10', '11', '12']]
>>> matriz[0][0]
'00'
>>> matriz[0][1]
'01'
>>> matriz[1][2]
'12'

A diferencia de los str las listas son mutables, es decir se pueden modificar sus elementos y podemos añadir nuevos elementos. Por ejemplo, podemos crear una lista y más tarde modificarla:

>>> lista = [10, 12, 12, 13]
>>> lista[1] = 11
>>> lista
[10, 11, 12, 13]

Además las listas posen varios métodos para añadir y eliminar elementos. append añade un nuevo elemento al final:

>>> lista.append(14)
>>> lista
[10, 11, 12, 13, 14]

Si queremos añadir no sólo un elemento sino toda una nueva lista de elementos al final podemos utilizar extend:

>>> lista2 = [15, 16, 17, 18]
>>> lista.extend(lista2)
>>> lista
[10, 11, 12, 13, 14, 15, 16, 17, 18]

Podemos eliminar elementos del final utilizando el método pop:

>>> lista.pop()
18
>>> lista
[10, 11, 12, 13, 14, 15, 16, 17]

Al ejecutar el método pop se nos devuelve el elemento que hemos eliminado y la lista queda mermada. Por supuesto el elemento devuelto podríamos haberlo guardado en una variable para trabajar con él. pop acepta un índice, por lo que también podríamos utilizarlo para eliminar un elemento del principio:

>>> primer_elemento = lista.pop(0)
>>> primer_elemento
10
>>> lista
[11, 12, 13, 14, 15, 16, 17]

Otro método que puede resultar útil es reverse. reverse invertirá el orden de los elementos de la lista:

>>> lista.reverse()
>>> lista
[17, 16, 15, 14, 13, 12, 11]

Si lo que deseamos es obtener una nueva lista invertida sin modificar la lista original podríamos haber utilizado la función reversed:

>>> list(reversed(lista))
[11, 12, 13, 14, 15, 16, 17]
>>> lista
[17, 16, 15, 14, 13, 12, 11]

reversed no devuelve una lista directamente sino un iterador. Más adelante vermos cual es la diferencia entre los iteradores y las listas.

Si lo que deseamos es ordenar la lista podemos utilizar el método sort:

>>> lista.sort()
>>> lista
[11, 12, 13, 14, 15, 16, 17]

Si queremos obtener una nueva lista ordenada dejando intacta la antigua podríamos utilizar la función sorted:

>>> sorted(lista)
[11, 12, 13, 14, 15, 16, 17]

sorted admite distintos parámetros, que se escapan un poco de esta pequeña introducción, pero que nos pueden resultar útiles si el orden que obtenemos no es el que deseamos o si estamos intentando ordenar listas en las que los elementos son objetos más complejos que un simple número o una cadena de texto.

Las diferencias de comportamiento entre métodos tan similares como reverse y reversed pueden resultar algo confusas para el programador neófito, pero lo importante es simplemente recordar que estos comportamientos alternativos existen. Si en cualquier momento tenemos dudas sobre qué comportamiento tiene cualquiera de los métodos o funciones siempre podemos abrir un intérprete de Python y hacer una pequeña prueba con una lista. Por lo tanto no necesitamos memorizar cual es el comportamiento exacto de cada función sino comprender cuales son estos posibles comportamientos.

min, max, sum

Python dispone de unas cuantas funciones que facilitan el trabajo con las listas, como por ejemplo min, max y sum. Estas funciones en realidad pueden operar sobre cualquier iterador y su funcionamiento es el que su nombre implica:

>>> min([1, 2, 3, 4])
1
>>> max([1, 2, 3, 4])
4
>>> sum([1, 2, 3, 4])
10

Función map

En muchas ocasiones nos puede interesar aplicar una función, un cálculo, sobre cada uno de los elementos de una lista o iterador. Esto podemos hacerlo con la función map. map necesita dos argumentos, la función a aplicar y la lista o iterador sobre el que aplicarlo. El resultado será una nueva lista, la resultante de aplicar la función a cada uno de los elementos de la lista original:

>>> map(str, [1, 2, 3, 4])
['1', '2', '3', '4']

Además de estos elementos de programación funcional Python dispone de una función filter que permite filtrar los elementos de una lista dependiendo de que verifiquen o no una condición dada. Una sintaxsis alternativa que permite obtener resultados similares es la de las list comprenhensions.

Ejercicios

  1. Separa la lista [‘id_paciente’, ‘fase1’, ‘37.1’, ‘39.3’, ‘38.1’] en tres variables: id_paciente, fase_ensayo, serie_temperaturas.

  2. Convierte los números (que están representados por cadenas de texto) de la serie de temperaturas anterior en números con coma flotante.

  3. Añade a la lista de números una nueva temperatura, 37.2.

  4. Añade a las temperaturas la lista: [36.5, 37.3].

  5. ¿Cuántas temperaturas tenemos en total?

  6. Obtén una cadena de texto con las temperaturas separadas por comas.

  7. Ordena las temperaturas de mayor a menor y viceversa.

  8. Obtén la media de las temperaturas.

  9. ¿Cuáles son las temperaturas máxima y mínima?

  10. Crea una lista con los números del 0 al 9 y extrae los pares, los impares, los 5 primeros y los 5 últimos por separado.

  11. Dada la siguiente secuencia:

>>> lista = ['spam', 'python', 'inquisicion']
>>> ordenada = sorted(lista)
>>> ordenada
['inquisicion', 'python', 'spam']
>>> lista
['spam', 'python', 'inquisicion']
>>> ordenada.reverse()
>>> ordenada
['spam', 'python', 'inquisicion']
>>> ordenada.reverse()
>>> inversa = list(reversed(ordenada))

¿Por qué queda intacta la primera lista después de haberla ordenado con sorted? ¿Por qué no sucede lo mismo cuando aplicamos reverse a la lista ordenada? ¿Cuál es la diferencia de comportamiento entre el método reverse y la función reversed? ¿Qué pasaría si hacemos inversa = lista.reverse(), a qué sería igual la variable inversa?

Soluciones

  1. Separa la lista [‘id_paciente’, ‘fase1’, ‘37.1’, ‘39.3’, ‘38.1’] en tres variables: id_paciente, fase_ensayo, serie_temperaturas.

>>> lista = ['id_paciente', 'fase1', '37.1', '39.3', '38.1']
>>> id_paciente = lista[0]
>>> fase_ensayo = lista[1]
>>> serie_temperaturas = lista[2:]
>>> id_paciente
'id_paciente'
>>> fase_ensayo
'fase1'
>>> serie_temperaturas
['37.1', '39.3', '38.1']
  1. Convierte los números (que están representados por cadenas de texto) de la serie de temperaturas anterior en números con coma flotante.

>>> serie_temperaturas = map(float, serie_temperaturas)
>>> serie_temperaturas
[37.100000000000001, 39.299999999999997, 38.100000000000001]
  1. Añade a la lista de números una nueva temperatura, 37.2.

>>> serie_temperaturas.append(37.2)
>>> serie_temperaturas
[37.100000000000001, 39.299999999999997, 38.100000000000001,
37.200000000000003]
  1. Añade a las temperaturas la lista: [36.5, 37.3].

>>> serie_temperaturas.extend([36.5, 37.3])
>>> serie_temperaturas
[37.100000000000001, 39.299999999999997, 38.100000000000001,
37.200000000000003, 36.5, 37.299999999999997]
  1. ¿Cuántas temperaturas tenemos en total?

>>> len(serie_temperaturas)
6
  1. Obtén una cadena de texto con las temperaturas separadas por comas.

>>> ','.join(map(str, serie_temperaturas))
'37.1,39.3,38.1,37.2,36.5,37.3'
  1. Ordena las temperaturas de mayor a menor y viceversa.

>>> sorted(serie_temperaturas)
[36.5, 37.100000000000001, 37.200000000000003, 37.299999999999997,
38.100000000000001, 39.299999999999997]
>>> list(reversed(sorted(serie_temperaturas)))
[39.299999999999997, 38.100000000000001, 37.299999999999997,
37.200000000000003, 37.100000000000001, 36.5]

O alternativamente:

>>> serie_ordenada = sorted(serie_temperaturas)
>>> serie_ordenada.reverse()
>>> serie_ordenada
[39.299999999999997, 38.100000000000001, 37.299999999999997,
37.200000000000003, 37.100000000000001, 36.5]
  1. Obtén la media de las temperaturas.

>>> sum(serie_temperaturas) / len(serie_temperaturas)
37.583333333333336
  1. ¿Cuáles son las temperaturas máxima y mínima?

>>> max(serie_temperaturas)
39.299999999999997
>>> min(serie_temperaturas)
36.5
  1. Crea una lista con los números del 0 al 9 y extrae los pares, los impares, los 5 primeros y los 5 últimos por separado.

>>> lista = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> pares = lista[::2]
>>> pares
[0, 2, 4, 6, 8]
>>> impares = lista[1::2]
>>> impares
[1, 3, 5, 7, 9]
>>> primeros = lista[:5]
>>> primeros
[0, 1, 2, 3, 4]
>>> ultimos = lista[-5:]
>>> ultimos
[5, 6, 7, 8, 9]

Alternativamente podríamos haber creado la lista con la función range():

>>> range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

En Python 3.x range es un iterador y deberíamos haber utilizado la expresión:

>>> list(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
  1. Dada la siguiente secuencia:

>>> lista = ['spam', 'python', 'inquisicion']
>>> ordenada = sorted(lista)
>>> ordenada
['inquisicion', 'python', 'spam']
>>> lista
['spam', 'python', 'inquisicion']
>>> ordenada.reverse()
>>> ordenada
['spam', 'python', 'inquisicion']
>>> ordenada.reverse()
>>> inversa = list(reversed(ordenada))

¿Por qué queda intacta la primera lista después de haberla ordenado con sorted?

Porque la función sorted crea una nueva lista dejando la original intacta.

¿Por qué no sucede lo mismo cuando aplicamos reverse a la lista ordenada?

Porque el método reverse da la vuelta a la lista sin crear una nueva, aprovecha el hecho de que la lista es mutable y la modifica.

¿Cuál es la diferencia de comportamiento entre el método reverse y la función reversed?

El método reverse modifica la lista original, pero la función reversed de modo análogo a la función sorted no modifica la lista original sino que devuelve un nuevo iterador que podemos transformar en una lista.

¿Qué pasaría si hacemos inversa = lista.reverse(), a qué sería igual la variable inversa?

El método reverse modifica la lista y por lo tanto no devuelve una nueva lista. La variable a la que asignemos el resultado quedará vacía.

Para saber más

  • Las secciones correspondientes a las listas en el tutorial oficial de Python (1 y 2), pueden ser una buena continuación a este breve tutorial.

  • Como para cualquier otra clase de objetos la ayuda disponible en el intérprete puede también ser muy útil. En este caso: help(list)