usort, uasort y uksort en PHP: ordenar arrays con criterio propio

PHP tiene funciones de ordenación con criterio fijo (sort(), asort(), ksort()...) y funciones de ordenación con criterio personalizable. usort() ordena un array usando un callback que tú defines; uasort() hace lo mismo pero preserva las asociaciones clave-valor; y uksort() ordena por las claves. Son las tres que necesitas cuando los criterios de ordenación van más allá del orden alfabético o numérico simple.

usort(): ordenar por criterio propio

<?php
usort(array &$array, callable $callback): bool
?>

El callback recibe dos elementos y debe devolver un entero negativo, cero o positivo según si el primero va antes, en la misma posición o después que el segundo. El operador spaceship (<=>, disponible desde PHP 7) simplifica esto enormemente:

<?php
$productos = [
    ['nombre' => 'Zapatillas', 'precio' => 89.90],
    ['nombre' => 'Camiseta',   'precio' => 19.90],
    ['nombre' => 'Pantalón',   'precio' => 39.90],
];

// Orden ascendente por precio
usort($productos, fn($a, $b) => $a['precio'] <=> $b['precio']);

foreach ($productos as $p) {
    echo $p['nombre'] . ': ' . $p['precio'] . "n";
}
// Camiseta: 19.9
// Pantalón: 39.9
// Zapatillas: 89.9
?>

Ordenar por múltiples campos

Cuando el primer campo tiene empate, el spaceship encadenado con || resuelve el desempate con el siguiente campo:

<?php
$empleados = [
    ['nombre' => 'Carlos', 'departamento' => 'IT',      'salario' => 3200],
    ['nombre' => 'Ana',    'departamento' => 'IT',      'salario' => 3800],
    ['nombre' => 'Marta',  'departamento' => 'Ventas',  'salario' => 2900],
    ['nombre' => 'Luis',   'departamento' => 'IT',      'salario' => 3200],
];

// Ordenar por departamento, luego por salario descendente, luego por nombre
usort($empleados, function($a, $b) {
    return $a['departamento'] <=> $b['departamento']
        ?: $b['salario'] <=> $a['salario']   // descendente: b <=> a
        ?: $a['nombre']  <=> $b['nombre'];
});
?>

Ordenar objetos por propiedad

<?php
class Articulo {
    public function __construct(
        public string $titulo,
        public DateTime $fecha,
        public int $visitas
    ) {}
}

$articulos = [
    new Articulo('PHP Arrays',  new DateTime('2024-03-10'), 1240),
    new Articulo('PHP Strings', new DateTime('2024-05-22'),  876),
    new Articulo('PHP 8.4',     new DateTime('2024-04-01'), 3150),
];

// Ordenar por visitas descendentes
usort($articulos, fn($a, $b) => $b->visitas <=> $a->visitas);

foreach ($articulos as $art) {
    echo "{$art->titulo}: {$art->visitas} visitasn";
}
// PHP 8.4: 3150 visitas
// PHP Arrays: 1240 visitas
// PHP Strings: 876 visitas
?>

uasort() y uksort()

<?php
// uasort: preserva claves, útil con arrays asociativos
$inventario = ['camiseta' => 45, 'pantalon' => 12, 'zapatillas' => 0, 'chaqueta' => 8];
uasort($inventario, fn($a, $b) => $b <=> $a); // descendente por valor

print_r($inventario);
// Array ( [camiseta] => 45 [pantalon] => 12 [chaqueta] => 8 [zapatillas] => 0 )

// uksort: ordena por las propias claves
$config = ['puerto' => 3306, 'host' => 'localhost', 'charset' => 'utf8mb4'];
uksort($config, fn($a, $b) => strcmp($a, $b));

print_r($config);
// Array ( [charset] => utf8mb4 [host] => localhost [puerto] => 3306 )
?>

Ordenación estable en PHP 8

Desde PHP 8.0, todas las funciones de ordenación (incluidas usort, uasort y uksort) son estables: elementos considerados iguales por el comparador mantienen su orden relativo original. En PHP 7 el orden de los empates era indefinido, lo que podía producir resultados distintos entre ejecuciones.

La documentación oficial de usort() incluye el historial de la estabilidad de ordenación y los cambios de comportamiento respecto a PHP 7.

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP