Objetivo: mostrar cómo ordenar los elementos de una lista.
Benditas sean las listas. ¡Qué sería de nosotros, pythonistas, sin su admirable flexibilidad! He perdido la cuenta de los problemas que he podido resolver con elegancia apoyándome simplemente en estas sólidas estructuras.
Vamos a ampliar el repertorio de las posibilidades que nos ofrecen las listas. Nos ocuparemos hoy de ordenarlas.
Tomemos, por ejemplo, la siguiente lista numérica:
>>> a = [7, -1, 5, 3]
Ordenarla resulta tan sencillo como aplicar el método sort(), disponible en los objetos de tipo lista:
>>> a.sort()
>>> a
[-1, 3, 5, 7]
Bien simple. No obstante hay algo que debes tener siempre presente: esta modificación es «in situ», atacando directamente al objeto original, sin crear una copia.
Si lo que quieres es generar una nueva lista ordenada, pero sin afectar la original, puedes hacer uso de la función sorted(), que toma como argumento una secuencia y devuelve otra diferente ordenada.
>>> a = [7, -1, 5, 3]
>>> b = sorted(a)
>>> a
[7, -1, 5, 3]
>>> b
[-1, 3, 5, 7]
Mucho cuidado con hacer esto:
>>> a = [7, -1, 5, 3]
>>> b = a.sort()
Naturalmente, a se modificaría, ordenándose. ¿Pero qué crees que valdría b?
>>> print(b)
None
Nada. b no vale nada.
Si no entiendes por qué sucede esto, no te pierdas la lectura del artículo Python – Hace falta valor, en el que se desentraña el misterio.
Lo bueno de la función sorted() es que el argumento puede ser una secuencia en general, no solamente una lista. Así, objetos no mutables, como las tuplas, que no disponen del método sort(), podrían beneficiarse de su utilización.
La única limitación de sort() y sorted() es que los elementos han de ser comparables. Si no, Python difícilmente podrá deducir su orden.
La siguiente lista, con tipos diferentes, no podrá ser ordenada por sort():
>>> listamixta = [1, 'a', 5, 'casa']
>>> listamixta.sort()
Traceback (most recent call last):
File "<pyshell#83>", line 1, in <module>
listamixta.sort()
TypeError: unorderable types: str() < int()
Ordenar una lista en sentido inverso, de mayor a menor, es igualmente fácil haciendo uso de un argumento opcional, reverse:
>>> a = [7, -1, 5, 3]
>>> a.sort(reverse = True)
>>> a
[7, 5, 3, -1]
La función sorted() dispone también de la misma posibilidad:
>>> a = [7, -1, 5, 3]
>>> sorted(a, reverse = True)
[7, 5, 3, -1]
Observa que, en este último ejemplo, a no ha modificado su valor, puesto que sorted() ha creado un objeto diferente:
>>> a
[7, -1, 5, 3]
Voy a plantearte ahora un problema interesante que servirá de preludio al argumento que presentaremos a continuación y que aumentará sobremanera la potencia de nuestras ordenaciones.
Imagina que queremos ordenar alfabéticamente la siguiente lista:
>>> frutas = ['pera', 'Manzana', 'fresa']
Observa que he comenzado en mayúsculas la palabra Manzana.
El método sort(), estrictamente, cumple su función:
>>> frutas.sort()
>>> frutas
['Manzana', 'fresa', 'pera']
Las letras mayúsculas se almacenan internamente con un código más bajo que las correspondientes minúsculas, de modo que Manzana aparece antes que fresa, pese a que tal vez no fuera eso lo que nos gustaría.
¿Cómo hacer para que la ordenación no tenga en cuenta que la M está en mayúsculas y la trate como si fuera minúscula, pero dejando que aparezca en el resultado tal como fue escrita?
Imagina que podemos crear un tratamiento temporal previo que procese cada término conviertiéndolo completamente en minúsculas para que luego sort trabaje sobre ese resultado, pero sin olvidar cuáles eran los términos originales.
Esto se logra con un nuevo argumento, key:
>>> frutas = ['pera', 'Manzana', 'fresa']
>>> frutas.sort(key = str.lower)
>>> frutas
['fresa', 'Manzana', 'pera']
Y ahora sí, fresa aparece antes que Manzana.
Presta atención: key recibe como valor el nombre de una función que requiera un único argumento. El valor devuelto por la función será utilizado después como base de trabajo para la ordenación.
El método lower(), que se aplica a los objetos de tipo str, strings, convierte una cadena de caracteres toda en minúsculas. Observa que he dicho el nombre de una función, por eso lower se muestra sin paréntesis en el argumento key.
Otro ejemplo. Reorganicemos nuestra macedonia, pero esta vez de modo que las frutas aparezcan ordenadas de acuerdo a su longitud:
>>> frutas = ['pera', 'Manzana', 'fresa']
>>> frutas.sort(key = len)
>>> frutas
['pera', 'fresa', 'Manzana']
Como sabes, la función len devuelve el número de elementos de una secuencia, esto es, el número de letras de que se compone un string, en nuestro caso. Ese total será tomado como criterio para la ordenación.
Podemos utilizar key para saltarnos la limitación que nos impedía ordenar listas mixtas.
>>> listamixta = [1, 'a', 5, 'casa']
>>> listamixta.sort(key = str)
>>> listamixta
[1, 5, 'a', 'casa']
La función str convierte un objeto en string, de modo que los números ya serán comparables con el resto de valores y sort() podrá realizar su trabajo. Observa que la lista resultado sigue siendo mixta; la conversión a string sólo se ha realizado a nivel interno.
Podemos ir más allá y crear incluso nuestras propias funciones para utilizarlas en sort().
Por ejemplo, esta sencilla función invierte un string:
>>> def invertir(cadena):
return cadena[::-1]
>>> invertir('pimiento')
'otneimip'
Si no entiendes cómo trabaja esta función, echa un vistazo al artículo El mundo al revés.
Vamos a aprovecharla entonces como criterio de ordenación para que sort() ordene la lista atendiendo a la última letra de cada palabra, en lugar de la primera, tal como haría por omisión.
>>> planetas = ['mercurio', 'venus', 'tierra', 'marte']
>>> planetas.sort(key = invertir)
>>> planetas
['tierra', 'marte', 'mercurio', 'venus']
Fíjate por dónde, nuestro planeta el primero…
La función sorted(), como cabría esperar, dispone también del argumento key.
Interesante. Las posibilidades creativas son inmensas. Prácticamente significa que puedes hacer que Python ordene una lista o, por lo general, cualquier secuencia, por cualquier criterio que puedas imaginar. Es lo que me encanta de Python: este lenguaje rezuma creatividad lo mires por donde lo mires.
Javier Montero Gabarró
Python – Un poco de orden, por favor
El texto de este artículo se encuentra sometido a una licencia Creative Commons del tipo CC-BY-NC-ND (reconocimiento, no comercial, sin obra derivada, 3.0 unported)
El Club del Autodidacta
Consulta el índice completo de artículos relacionados con Python.