Ordenación de objetos en Python

Python

Sinceramente, haces esto en Visual Basic 6, o en cualquier otro lenguaje me hubiera llevado una infinidad de tiempo escribiendo líneas de código, pero en Python …. las cosas son bastante sencillas, … si sabes hacerlas, claro!

Ordenar listas … de objetos

El ejemplo que voy a tratar en la entrada de hoy es cómo ordenar listas de objetos, así que … vamos a empezar viendo cómo se ordena una lista muy simple.

Esto es fácil, usando el built-in sorted.

milista = [4,1,8,2,9]
print sorted(milista)

 

Sencillo, no?

Ordenar listas

Ordenar listas

Ahora, vamos a complicar la cosa, y lo que queremos ordenar son varios objetos que tenemos en una lista. Lo primero es crear una función para que me imprima la lista, y así poder ver el resultato. El siguiente paso es definir un objeto, para nuestro ejemplo, con 2 propiedades, que llamaremos campo1 y campo2.

Para ordenar por el campo1, podemos hacer uso de las funciones lambda, tal que así:

vv2 = sorted(vv, key=lambda objeto: objeto.campo1)

 

De esta forma, se ordena sólamente por el campo1, obteniendo este resultado:

Ordenación de listas de objetos

Ordenación de listas de objetos

Si queremos invertir el orden, podemos incorporar el parámetro reverse=True.

Ordenación de listas de objetos por más de un campo

En la imágen anterior se puede comprobar de que está ordenado, efectivamente, por el campo1, pero lo ideal es que sea ordenado primero por el campo1, y después por el campo2. Para ello, la mejor opción es utilizar uno de los métodos mágicos de Python.

¿Métodos mágicos? Si no sabes de qué te estoy hablando ….  te recomiendo que te leas bien este documento: , pues te facilitará la vida, especialmente si tienes que trabajar con clases (y tarde o temprano acabaras haciéndolo, así que …. ).

El caso es que toca modificar la clase Ejemplo, y definir el método mágico para comparar, y aquí es donde aplicamos la lógica de ordenación. La clase modificada queda así:


class Ejemplo():
def __init__(self, campo1, campo2):
self.campo1 = campo1
self.campo2 = campo2
def __str__(self):
return "%s - %s" % (self.campo1, self.campo2)

def __cmp__(self, other):
if self.campo1 == other.campo1:
return 1 if self.campo2 > other.campo2 else -1
elif self.campo1 < other.campo1:
return -1
else:
return 1

Los valores 1 indican que self está por delante de other. El 0 es que los objetos tienen los mismos valores de comparación, mientras que cuando devuelve -1 es porque other está por delante the self.

Ahora no es necesario especificar el parámetro key dentro de sorted, ya que aplicará el método mágico que hemos definido.

El resultado es el deseado:

Ordenación de listas de objetos

Ordenación de listas de objetos

El código completo es este:


#-------------------------------------------------------------------------------
# Copyright:   (c)Manejando datos 2014
#-------------------------------------------------------------------------------
miVersion = "Ordenación de objetos con Python - version 0.2.0"

class Ejemplo():
def __init__(self, campo1, campo2):
self.campo1 = campo1
self.campo2 = campo2
def __str__(self):
return "%s - %s" % (self.campo1, self.campo2)

def __cmp__(self, other):
if self.campo1 == other.campo1:
return 1 if self.campo2 > other.campo2 else -1
elif self.campo1 < other.campo1:
return -1
else:
return 1

def lista(vv):
""" Imprimimos la lista"""
for v in vv:
print (v)

# Definimos varios objetos
v1 = Ejemplo("rojo", 10)
v2 = Ejemplo("rojo", 8)
v3 = Ejemplo("rojo", 16)
v4 = Ejemplo("rojo", 11)
v5 = Ejemplo("amarillo", 10)
v6 = Ejemplo("amarillo", 8)
v7 = Ejemplo("verde", 14)
v8 = Ejemplo("verde", 12)
v9 = Ejemplo("verde", 8)

# Creamos la Lista
vv = [v1, v2, v3, v4, v5, v6, v7, v8, v9]
vv2 = sorted(vv, key=lambda objeto: objeto.campo1, reverse=True)
#lista(vv2)
print " -------"
vv3 = sorted(vv)
lista(vv3)

En resumen, que la ordenación de listas de objetos no tiene mucha complejidad, aunque sí es cierto que requiere de algunos conocimientos un poco más expertos.

Como siempre, dejo el código Python en GitHub. Y el editor que he usado es PyScripter, del que te he hablado aquí en varias ocasiones, y para estos pequeños códigos es muy útil!