RustArena

Step 5 of 7

Sorting

sort() puts a vector in ascending order, in place. reverse() flips the order.

fn main() {
    let mut scores = vec![88, 42, 97, 61, 42];
    scores.sort();
    println!("{:?}", scores);
    scores.reverse();
    println!("{:?}", scores);

    let mut names = vec!["mika", "Ana", "bo", "Zed"];
    names.sort();
    println!("{:?}", names);
    names.sort_by_key(|name| name.to_lowercase());
    println!("{:?}", names);
}
[42, 42, 61, 88, 97]
[97, 88, 61, 42, 42]
["Ana", "Zed", "bo", "mika"]
["Ana", "bo", "mika", "Zed"]

Strings sort by their character codes, and every uppercase letter comes before every lowercase one, so "Zed" lands before "bo". To sort ignoring case, sort_by_key sorts by a key computed from each element.

|name| name.to_lowercase() is a closure: a small function without a name, written right where it's used. Between the bars are its parameters; after them comes the value it returns. Here: "given a name, the key is its lowercase version". Module 26 covers closures in depth; for sorting, this shape is all you need.

Custom orders with sort_by

sort_by takes a closure that compares two elements and returns an Ordering (Less, Equal or Greater). a.cmp(&b) produces one:

fn main() {
    let mut results = vec![("bo", 72), ("ana", 91), ("dee", 72), ("cy", 85)];

    results.sort_by(|a, b| b.1.cmp(&a.1).then(a.0.cmp(b.0)));
    for (name, score) in &results {
        println!("{name}: {score}");
    }

    let mut lap_times: Vec<f64> = vec![61.2, 59.8, 60.5];
    lap_times.sort_by(|a, b| a.total_cmp(b));
    println!("{:?}", lap_times);
}
ana: 91
cy: 85
bo: 72
dee: 72
[59.8, 60.5, 61.2]

Stable and unstable

sort, sort_by and sort_by_key are stable: elements that compare equal keep their original order. sort_unstable (and sort_unstable_by, sort_unstable_by_key) may reorder equal elements but is a little faster and needs no extra memory. For plain numbers you can't tell equal values apart, so sort_unstable is a good default there.

Common mistakes

Your task

Write fn top_three(scores: &[u32]) -> Vec<u32> that returns the three highest scores, highest first (fewer if there are fewer than three). You can't sort through a shared &[u32] borrow, so start with let mut sorted = scores.to_vec();, which copies it into a new vector you own.

Challenge 2

Write fn sort_by_length(words: &mut [String]) that sorts words from shortest to longest, with words of the same length in alphabetical order. Use sort_by with .then(...), or use the fact that sorting is stable: sort alphabetically first, then sort_by_key(|w| w.len()).

Challenge 3

Write a program that reads race times in seconds (one per line, like 9.58) and prints them fastest first, numbered, with two decimals:

1. 9.58
2. 9.69
3. 9.72

Remember that f64 can't use sort().

Previous: Insert, remove, swap, truncate, clear Next: dedup, retain, contains and binary_search