HOWTO · Rust

Ordenar un vector en Rust

Las funciones sort_by() y sort() toman como referencia el vector y lo devuelven ordenado. Los valores se ordenan en orden ascendente de forma predeterminada.

En esta página

Para ordenar un vector de Rust de forma ascendente, llama a sort() sobre un vector mutable. El método reordena el vector existente según el orden natural de sus elementos. Usa sort_by() cuando necesites comparar campos concretos o definir otro criterio de ordenación. Ambos métodos forman parte de la biblioteca estándar de Rust.

Ordenar en el sitio con sort()

sort() es la opción directa cuando el tipo de los elementos tiene un orden total natural. El vector debe ser mutable, ya que la ordenación reorganiza sus elementos. El tipo debe implementar el trait Ord; los enteros y las cadenas lo implementan, pero los tipos de punto flotante no.

Ejecuta este ejemplo:

fn main() {
    let mut numbers = vec![5, 3, 8, 1, 2];
    numbers.sort();
    println!("{:?}", numbers);
}

Después de la llamada, numbers contiene los mismos valores en orden ascendente. El método ordena el vector existente en lugar de devolver otro vector ya ordenado, así que usa una vinculación mutable si necesitas conservar el resultado.

Para un vector de cadenas, sort() también usa el orden natural del tipo. Si necesitas orden descendente, usa sort_by() e invierte la comparación, por ejemplo, con |a, b| b.cmp(a). Elige el criterio de forma deliberada cuando el orden natural no coincida con la manera en que tu aplicación presenta o agrupa los valores.

Usar sort_by() para definir un orden personalizado

sort_by() recibe una clausura comparadora. Rust la llama con dos elementos y esta devuelve un valor Ordering: Less, Equal o Greater. Se comparan pares de elementos; no se proporciona una función clave que devuelva una clave para cada elemento. El método cmp() de los valores que implementan Ord es una forma práctica de obtener ese resultado.

Este ejemplo ordena las tuplas por su segundo campo, de menor a mayor:

fn main() {
    let mut pairs = vec![(1, 3), (2, 1), (3, 2)];
    pairs.sort_by(|a, b| a.1.cmp(&b.1));
    println!("{:?}", pairs);
}

La clausura compara a.1 con b.1; no modifica los valores de las tuplas. Para ordenar por varios campos, compara primero el campo principal y usa otra comparación para resolver los empates. Mantén la comparación coherente: para un mismo par de valores, debe expresar una relación de orden estable. sort_by() también modifica el vector en el sitio, por lo que se aplica la misma regla de vinculación mutable.

Ordenar valores de punto flotante de forma segura

Los tipos f32 y f64 de Rust implementan PartialOrd, pero no Ord. Se pueden comparar la mayoría de los valores finitos, pero las comparaciones que involucran NaN no producen un orden. Por eso no se puede llamar directamente a sort() en un vector de valores de punto flotante, y por eso desempaquetar el resultado de partial_cmp() puede provocar un pánico si un valor es NaN.

Si la política deseada es el orden total de Rust para valores de punto flotante, usa total_cmp() en la comparación. Este define un orden que incluye NaN y distingue el cero negativo del positivo. El siguiente ejemplo autónomo incluye un NaN para que la política elegida quede clara:

fn main() {
    let mut values = vec![3.5_f64, f64::NAN, -1.0, 2.0];
    values.sort_by(f64::total_cmp);
    println!("{:?}", values);
}

total_cmp() resulta útil cuando todos los valores de punto flotante deben participar en un único orden determinista. Si tu aplicación necesita colocar todos los valores NaN al final o rechazarlos, expresa esa política de forma explícita en la comparación o valida los datos antes de ordenarlos. Un orden total es una regla de comparación; no determina qué política es la adecuada para tus datos.