Ordenar listas en Python

En mi sistema de registro de productos para un supermercado, recibí una lista con algunos productos:
[nombre:chocolate valor:3.45,
nombre:galleta valor:2.49,
nombre:cafe valor:3.45,
nombre:jugo valor:4.3,
nombre:porotos valor:10.0,
nombre:arroz valor:8.5]
Cada producto es un objeto del tipo Producto, está representado por la siguiente clase:
class Producto(object):
def __init__(self, nombre, valor):
self.__nombre = nombre
self.__valor = valor
def __repr__(self):
return "nombre:%s valor:%s" % (self.__nombre, self.__valor)
def get_nombre(self):
return self.__nombre
def get_valor(self):
return self.__valor
Note que la lista tiene productos en orden aleatorio. Pero, necesito ordenarlos, es decir, saber cuáles son los productos más caros o los más baratos, o también, ordenarlos por el nombre para facilitar la visualización de los productos. Entonces, ¿cómo lo podemos hacer?
Ordenar lista de números
En Python, cuando necesitamos ordenar listas, podemos utilizar la función sorted, por ejemplo, para una lista de números:
numeros = [4,2,6,1,3]
numeros_ordenados = sorted(numeros)
print numeros
print numeros_ordenados
Tenemos el siguiente resultado:
[4, 2, 6, 1, 3]
[1, 2, 3, 4, 6]
Ordenar lista de strings
¡Funciona perfectamente! Pero, ¿también funciona para textos? Veamos:
palabras = ["chocolate","galleta", "cafe", "jugo", "porotos", "arroz"]
palabras_ordenadas = sorted(palabras)
print palabras
print palabras_ordenadas
Entonces, tenemos el siguiente resultado:
['chocolate', 'galleta', 'cafe', 'jugo', 'porotos', 'arroz']
['arroz', 'cafe', 'chocolate', 'galleta', 'jugo', 'porotos']
Ordenar lista de objetos
¡Aparentemente funciona con todo! Entonces, también podemos usarlo para objetos:
productos = lista_productos()
productos_ordenados = sorted(productos)
print productos
print productos_ordenados
Veamos el resultado:
[nombre:chocolate valor:3.45,
nombre:galleta valor:2.49,
nombre:cafe valor:3.45,
nombre:jugo valor:4.3,
nombre:porotos valor:10.0,
nombre:arroz valor:8.5]
[nombre:chocolate valor:3.45,
nombre:galleta valor:2.49,
nombre:cafe valor:3.45,
nombre:jugo valor:4.3,
nombre:porotos valor:10.0,
nombre:arroz valor:8.5]
Criterio de ordenación de objetos
Oye, ¿no debería ordenar? Debería, pero primero necesitamos hacernos las siguientes preguntas:
- ¿Cómo ordenamos un objeto del tipo
Producto
? - ¿Por el atributo
nombre
? ¿O por elvalor
?
Observe que, en principio no sabemos, pues en determinados momentos, podemos querer ordenar por nombre o por valor. En otras palabras, el sorted
, en principio, ¡también no sabe cómo ordenar nuestro objeto!
Supongamos que queremos ordenar por nombre
, ¿cómo el sorted
sabría eso? ¡No lo informamos en ningún momento!
Por lo tanto, cuando queremos ordenar un objeto del tipo Producto, debemos informar ¡por qué atributo se ordenará!
Definir criterio de ordenación del objeto
Para informar al sorted por qué atributo deseamos que ordene, debemos enviar el parámetro key con el valor del atributo de la clase deseada. Intentemos por el atributo valor
:
productos_ordenados = sorted(productos, key = Producto.get_valor)
Observe que, en este caso, estamos utilizando el get_valor
justamente por estar escondiendo el atributo. Veamos ahora el resultado:
[nombre:chocolate valor:3.45,
nombre:galleta valor:2.49,
nombre:cafe valor:3.45,
nombre:jugo valor:4.3,
nombre:porotos valor:10.0,
nombre:arroz valor:8.5]
[nombre:galleta valor:2.49,
nombre:chocolate valor:3.45,
nombre:cafe valor:3.45,
nombre:jugo valor:4.3,
nombre:arroz valor:8.5,
nombre:porotos valor:10.0]
¡Vea que ahora nuestros objetos se ordenaron por el valor! En otras palabras, ahora están ordenados desde los más baratos hacia los más caros :D
¿Intentemos también por el nombre
? Alteremos y veamos si resulta:
productos_ordenados = sorted(productos, key = Producto.get_nome)
Entonces, tenemos el siguiente resultado:
[nombre:chocolate valor:3.45,
nombre:galleta valor:2.49,
nombre:cafe valor:3.45,
nombre:jugo valor:4.3,
nombre:porotos valor:10.0,
nombre:arroz valor:8.5]
[nombre:arroz valor:8.5,
nombre:galleta valor:2.49,
nombre:cafe valor:3.45,
nombre:chocolate valor:3.45,
nombre:porotos valor:10.0,
nombre:jugo valor:4.3]
Realizar ordenación reversa
¡Maravilla! ¡Funcionó como lo esperado! Sin embargo, ¿si quisiera el orden inverso? Es decir, desde el más caro hacia el más barato, o entonces, desde la letra "z" hacia la "a", ¿cómo lo haremos?
¡Sencillo! basta agregar el parámetro reverse
con el valor True
. Veamos el resultado ordenando por el valor
:
productos_ordenados = sorted(productos, key = Producto.get_valor, reverse=True)
Tenemos el siguiente resultado:
[nombre:chocolate valor:3.45,
nombre:galleta valor:2.49,
nombre:cafe valor:3.45,
nombre:jugo valor:4.3,
nombre:porotos valor:10.0,
nombre:arroz valor:8.5]
[nombre:porotos valor:10.0,
nombre:arroz valor:8.5,
nombre:jugo valor:4.3,
nombre:chocolate valor:3.45,
nombre:cafe valor:3.45,
nombre:galleta valor:2.49]
Ahora con el nombre:
productos_ordenados = sorted(productos, key = Producto.get_nombre, reverse=True)
Probando el código nuevamente:
[nombre:chocolate valor:3.45,
nombre:galleta valor:2.49,
nombre:cafe valor:3.45,
nombre:jugo valor:4.3,
nombre:porotos valor:10.0,
nombre:arroz valor:8.5]
[nombre:jugo valor:4.3,
nombre:porotos valor:10.0,
nombre:chocolate valor:3.45,
nombre:cafe valor:3.45,
nombre:galleta valor:2.49,
nombre:arroz valor:8.5]
¡Funciona perfectamente! Un recurso muy fácil que no exige innúmeras implementaciones para que funcione :)
Vimos en esta publicación que, cuando queremos ordenar listas en Python, podemos usar la función sorted
. También vimos que funciona perfectamente para strings o números, sin embargo, cuando queremos ordenar objetos, debemos informar cómo debe ordenar el objeto, es decir, enviando un atributo del objeto por medio del parámetro key
.
¿Qué tal aprender más sobre Python y sus diversos recursos? Entonces, ¡mira nuestros cursos de Python para Data Science aquí en Alura!