Python ofrece dos formas de ordenar: sorted() devuelve una nueva lista ordenada sin modificar el original, y list.sort() modifica la lista en sitio y devuelve None. Ambas comparten los parámetros key= y reverse=, que son la clave para cualquier ordenación no trivial.
sorted() vs sort()
numeros = [3, 1, 4, 1, 5, 9, 2, 6]
# sorted(): no modifica la original, devuelve nueva lista
ordenados = sorted(numeros)
print(ordenados) # [1, 1, 2, 3, 4, 5, 6, 9]
print(numeros) # [3, 1, 4, 1, 5, 9, 2, 6] intacta
# sort(): modifica in-place, devuelve None
numeros.sort()
print(numeros) # [1, 1, 2, 3, 4, 5, 6, 9]
# sorted() funciona con cualquier iterable; sort() solo con listas
print(sorted("python")) # ['h', 'n', 'o', 'p', 't', 'y']
print(sorted((5, 3, 1))) # [1, 3, 5]
El parámetro key=
frutas = ["naranja", "kiwi", "manzana", "pera", "uva"] # Ordenar por longitud print(sorted(frutas, key=len)) # ['kiwi', 'uva', 'pera', 'naranja', 'manzana'] # Ordenar sin distinguir mayúsculas/minúsculas palabras = ["Python", "java", "Go", "RUST", "kotlin"] print(sorted(palabras, key=str.lower)) # ['Go', 'java', 'kotlin', 'Python', 'RUST'] # Ordenar por el último carácter print(sorted(frutas, key=lambda s: s[-1]))
Ordenar objetos propios
from dataclasses import dataclass
@dataclass
class Producto:
nombre: str
precio: float
stock: int
productos = [
Producto("Teclado", 89.99, 50),
Producto("Ratón", 29.99, 100),
Producto("Monitor", 349.0, 15),
Producto("Auriculares", 59.99, 30),
]
# Por precio
por_precio = sorted(productos, key=lambda p: p.precio)
for p in por_precio:
print(f"{p.nombre}: {p.precio}")
# Con operator.attrgetter (más rápido que lambda para atributos)
from operator import attrgetter
por_stock = sorted(productos, key=attrgetter("stock"))
# Por precio descendente
mas_caros = sorted(productos, key=lambda p: p.precio, reverse=True)
Ordenar diccionarios
inventario = {"manzanas": 150, "peras": 80, "naranjas": 210, "kiwis": 45}
# Ordenar por clave
por_clave = dict(sorted(inventario.items()))
print(por_clave)
# Ordenar por valor descendente
por_cantidad = dict(sorted(inventario.items(), key=lambda x: x[1], reverse=True))
print(por_cantidad)
# {'naranjas': 210, 'manzanas': 150, 'peras': 80, 'kiwis': 45}
# Con operator.itemgetter
from operator import itemgetter
por_cantidad = dict(sorted(inventario.items(), key=itemgetter(1), reverse=True))
Ordenación multicriterio
empleados = [
{"nombre": "Ana", "dept": "tech", "salario": 45000},
{"nombre": "Luis", "dept": "ventas", "salario": 38000},
{"nombre": "María", "dept": "tech", "salario": 52000},
{"nombre": "Juan", "dept": "ventas", "salario": 38000},
]
# Ordenar por departamento y luego por salario descendente
resultado = sorted(
empleados,
key=lambda e: (e["dept"], -e["salario"])
)
for e in resultado:
print(f"{e['dept']}: {e['nombre']} ({e['salario']})")
# tech: María (52000)
# tech: Ana (45000)
# ventas: Luis (38000) o Juan (38000) orden estable
# Con itemgetter para múltiples campos
from operator import itemgetter
por_dept_nombre = sorted(empleados, key=itemgetter("dept", "nombre"))
El algoritmo de Python (Timsort) es estable: elementos con la misma clave mantienen el orden relativo original. Eso permite ordenar en dos pasadas: primero por criterio secundario, luego por el principal, obteniendo el resultado correcto.
