Rust sorting
last modified November 13, 2026
In this article we show how to sort data in Rust.
Sorting methods are defined on slices, so they work on vectors, arrays, and parts of them. All of them sort in place: they rearrange the elements and return nothing. There are two families:
sort,sort_by,sort_by_key, andsort_by_cached_keyare stable: equal elements keep their relative ordersort_unstable,sort_unstable_by, andsort_unstable_by_keymay reorder equal elements, but are usually faster and do not allocate
Sorting relies on the Ord trait, a total order in which any
two values can be compared. The cmp method returns an
Ordering: Less, Equal, or
Greater. The examples were tested with Rust 1.97 and the 2024
edition. They are run as Cargo projects with cargo run -q.
Sorting in ascending order
The sort method sorts elements in their natural ascending
order.
fn main() {
let mut nums = vec![5, -2, 9, 0, 3, 3, -7];
nums.sort();
println!("{nums:?}");
nums.reverse();
println!("{nums:?}");
let mut words = vec!["pear", "Apple", "banana", "apple", "Zebra", "éclair"];
words.sort();
println!("{words:?}");
let mut arr = [3, 1, 2];
arr.sort();
println!("{arr:?}");
let mut letters: Vec<char> = "rustacean".chars().collect();
letters.sort();
let s: String = letters.into_iter().collect();
println!("{s}");
}
Integers are sorted numerically, and reverse turns the result
into descending order.
let mut words = vec!["pear", "Apple", "banana", "apple", "Zebra", "éclair"]; words.sort();
Strings are compared byte by byte. In UTF-8, all uppercase ASCII letters come before lowercase ones, and accented letters come after them both. This is not a dictionary order; we fix it later with a key function.
let mut letters: Vec<char> = "rustacean".chars().collect(); letters.sort();
To sort the characters of a string, we collect them into a vector, sort it, and collect them back. Sorted letters are a common way to detect anagrams.
$ cargo run -q [-7, -2, 0, 3, 3, 5, 9] [9, 5, 3, 3, 0, -2, -7] ["Apple", "Zebra", "apple", "banana", "pear", "éclair"] [1, 2, 3] aacenrstu
Custom comparisons with sort_by
The sort_by method takes a closure that compares two elements
and returns an Ordering.
use std::cmp::Ordering;
fn main() {
let mut nums: Vec<i32> = vec![5, -2, 9, 0, 3, -3, -7];
nums.sort_by(|a, b| b.cmp(a));
println!("descending: {nums:?}");
nums.sort_by(|a, b| a.abs().cmp(&b.abs()).then(a.cmp(b)));
println!("by absolute value: {nums:?}");
nums.sort_by(|a, b| match (a % 2 == 0, b % 2 == 0) {
(true, false) => Ordering::Less,
(false, true) => Ordering::Greater,
_ => a.cmp(b),
});
println!("even first: {nums:?}");
println!("{:?} {:?} {:?}", 1.cmp(&2), 2.cmp(&2), "b".cmp("a"));
}
Swapping the arguments of cmp reverses the order.
nums.sort_by(|a, b| b.cmp(a));
This sorts in descending order in a single step.
nums.sort_by(|a, b| a.abs().cmp(&b.abs()).then(a.cmp(b)));
We can compare derived values. Here the numbers are ordered by their
absolute value; when two absolute values are equal, as for 3 and -3, the
then method breaks the tie with a normal comparison. The
vector needs an explicit Vec<i32> type: the
abs method cannot be called on an integer of a not yet
inferred type.
nums.sort_by(|a, b| match (a % 2 == 0, b % 2 == 0) {
(true, false) => Ordering::Less,
(false, true) => Ordering::Greater,
_ => a.cmp(b),
});
A comparator can return an Ordering built by hand. Even
numbers come before odd ones; numbers of the same parity are compared
normally.
$ cargo run -q descending: [9, 5, 3, 0, -2, -3, -7] by absolute value: [0, -2, -3, 3, 5, -7, 9] even first: [-2, 0, -7, -3, 3, 5, 9] Less Equal Greater
Sorting by a key
Often it is simpler to say what to sort by. The sort_by_key
method calls a closure that extracts a key from each element.
use std::cmp::Reverse;
fn main() {
let mut words = vec!["banana", "fig", "cherry", "kiwi", "apple", "plum"];
words.sort_by_key(|w| w.len());
println!("{words:?}");
words.sort_by_key(|w| Reverse(w.len()));
println!("{words:?}");
let mut names = vec!["peter", "Anna", "boris", "Cyril", "anna"];
names.sort();
println!("{names:?}");
names.sort_by_key(|n| n.to_lowercase());
println!("{names:?}");
}
We sort fruit names by their length.
words.sort_by_key(|w| w.len()); words.sort_by_key(|w| Reverse(w.len()));
The std::cmp::Reverse wrapper reverses the order of a key.
Words of equal length keep their previous relative order because the sort
is stable.
names.sort_by_key(|n| n.to_lowercase());
Comparing lowercase versions of the strings gives a case-insensitive
order. Anna stays before anna because they have
the same key and Anna came first.
$ cargo run -q ["fig", "kiwi", "plum", "apple", "banana", "cherry"] ["banana", "cherry", "apple", "kiwi", "plum", "fig"] ["Anna", "Cyril", "anna", "boris", "peter"] ["Anna", "anna", "boris", "Cyril", "peter"]
Caching expensive keys
The sort_by_key method calls the key function on every
comparison. When the key is expensive to compute,
sort_by_cached_key computes it once per element.
use std::cell::Cell;
fn main() {
let words: Vec<String> = ["Delta", "alpha", "Echo", "charlie", "Bravo", "foxtrot", "golf", "Hotel"]
.iter()
.map(|s| s.to_string())
.collect();
let calls = Cell::new(0);
let key = |s: &String| {
calls.set(calls.get() + 1);
s.to_lowercase()
};
let mut a = words.clone();
a.sort_by_key(key);
println!("sort_by_key: {} key calls", calls.get());
calls.set(0);
let mut b = words.clone();
b.sort_by_cached_key(key);
println!("sort_by_cached_key: {} key calls", calls.get());
println!("{b:?} {}", a == b);
}
The key function counts its calls in a Cell.
let key = |s: &String| {
calls.set(calls.get() + 1);
s.to_lowercase()
};
The to_lowercase method allocates a new String
each time it is called.
a.sort_by_key(key); b.sort_by_cached_key(key);
For eight strings, sort_by_key computed 24 keys, two for each
comparison. The cached version computed exactly eight and then sorted the
precomputed keys. The difference grows with the size of the input. For
cheap keys such as a field or a length, plain sort_by_key is
faster.
$ cargo run -q sort_by_key: 24 key calls sort_by_cached_key: 8 key calls ["alpha", "Bravo", "charlie", "Delta", "Echo", "foxtrot", "golf", "Hotel"] true
Floats cannot be sorted with sort
Floating-point numbers implement only PartialOrd, not
Ord.
fn main() {
let mut temps = vec![21.5, 19.0, 23.25, 18.5];
temps.sort();
println!("{temps:?}");
}
The reason is the NaN value, which is neither smaller, equal to, nor greater than any number, including itself. Floats therefore have no total order.
temps.sort();
The sort method requires T: Ord, so the call
does not compile.
$ cargo run -q
error[E0277]: the trait bound `{float}: std::cmp::Ord` is not satisfied
--> src/main.rs:3:11
|
3 | temps.sort();
| ^^^^ the trait `std::cmp::Ord` is not implemented for `{float}`
|
= help: the following other types implement trait `std::cmp::Ord`:
i128
i16
i32
i64
i8
isize
u128
u16
and 4 others
note: required by a bound in `std::slice::<impl [T]>::sort`
--> /home/user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/slice.rs:133:12
|
131 | pub fn sort(&mut self)
| ---- required by a bound in this associated function
132 | where
133 | T: Ord,
| ^^^ required by this bound in `std::slice::<impl [T]>::sort`
For more information about this error, try `rustc --explain E0277`.
Sorting floats
The total_cmp method defines a total order for floats,
including NaN, and is the right way to sort them.
fn main() {
let mut temps = vec![21.5, 19.0, -0.0, 23.25, 0.0, 18.5, f64::NAN, -3.0, f64::INFINITY];
temps.sort_by(|a, b| a.total_cmp(b));
println!("{temps:?}");
temps.sort_by(|a, b| b.total_cmp(a));
println!("{temps:?}");
let mut clean: Vec<f64> = temps.iter().copied().filter(|t| !t.is_nan()).collect();
clean.sort_by(|a, b| a.partial_cmp(b).unwrap());
println!("{clean:?}");
let max = clean.iter().copied().fold(f64::NEG_INFINITY, f64::max);
println!("max {max}");
}
The data contains a NaN, an infinity, and both zeros.
temps.sort_by(|a, b| a.total_cmp(b));
The total_cmp method follows the IEEE 754 total ordering:
negative zero comes before positive zero, and a positive NaN is greater
than infinity. Swapping the arguments sorts in descending order.
let mut clean: Vec<f64> = temps.iter().copied().filter(|t| !t.is_nan()).collect(); clean.sort_by(|a, b| a.partial_cmp(b).unwrap());
When the NaNs are removed first, partial_cmp always returns
Some and can be unwrapped. It treats 0.0 and
-0.0 as equal, so they stay in their previous order.
$ cargo run -q [-3.0, -0.0, 0.0, 18.5, 19.0, 21.5, 23.25, inf, NaN] [NaN, inf, 23.25, 21.5, 19.0, 18.5, 0.0, -0.0, -3.0] [-3.0, 0.0, -0.0, 18.5, 19.0, 21.5, 23.25, inf] max inf
partial_cmp with NaN
Unwrapping partial_cmp on data that contains a NaN panics.
fn main() {
let mut data = vec![2.5, f64::NAN, 1.0];
data.sort_by(|a, b| a.partial_cmp(b).unwrap());
println!("{data:?}");
}
Comparing NaN with any number returns None.
data.sort_by(|a, b| a.partial_cmp(b).unwrap());
The unwrap call panics as soon as the sort compares the NaN.
Data from files and sensors can contain NaN values, so
total_cmp is the safer choice. The thread ID in the panic
message changes from run to run.
$ cargo run -q thread 'main' (138215) panicked at src/main.rs:3:42: called `Option::unwrap()` on a `None` value note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace $ echo $? 101
Stable and unstable sorting
A stable sort keeps the original order of elements that compare equal.
fn main() {
let orders = [
("anna", "books"),
("boris", "music"),
("cyril", "books"),
("dana", "garden"),
("emil", "music"),
("fero", "books"),
];
let mut stable = orders.to_vec();
stable.sort_by_key(|o| o.1);
println!("stable:");
for (name, cat) in &stable {
println!(" {cat:<7} {name}");
}
let mut unstable = orders.to_vec();
unstable.sort_unstable_by_key(|o| o.1);
let cats: Vec<_> = unstable.iter().map(|o| o.1).collect();
println!("unstable keys: {cats:?}");
}
The orders are listed by customer name and we sort them by category.
stable.sort_by_key(|o| o.1);
Within each category the names remain alphabetical, because that was their order before sorting. This lets us sort by several keys in succession: first by the secondary key, then by the primary one.
unstable.sort_unstable_by_key(|o| o.1);
The unstable sort produces the same sequence of keys, but gives no guarantee about the order of names within a category. Use it when equal elements are indistinguishable, for example plain numbers.
$ cargo run -q stable: books anna books cyril books fero garden dana music boris music emil unstable keys: ["books", "books", "books", "garden", "music", "music"]
Sorting by multiple keys
A comparison by several fields can be built by chaining
Ordering values or by using a tuple as the key.
use std::cmp::Reverse;
#[derive(Debug)]
struct Player {
name: &'static str,
team: &'static str,
score: u32,
}
fn main() {
let mut players = vec![
Player { name: "Lucia", team: "red", score: 42 },
Player { name: "Adam", team: "blue", score: 37 },
Player { name: "Marek", team: "red", score: 51 },
Player { name: "Jana", team: "blue", score: 51 },
Player { name: "Ivan", team: "red", score: 37 },
];
players.sort_by(|a, b| {
a.team
.cmp(b.team)
.then_with(|| b.score.cmp(&a.score))
.then_with(|| a.name.cmp(b.name))
});
for p in &players {
println!("{:<5} {:>3} {}", p.team, p.score, p.name);
}
println!();
players.sort_by_key(|p| (Reverse(p.score), p.name));
for p in &players {
println!("{:>3} {:<6} {}", p.score, p.name, p.team);
}
}
We sort players by team, then by score in descending order, then by name.
a.team
.cmp(b.team)
.then_with(|| b.score.cmp(&a.score))
.then_with(|| a.name.cmp(b.name))
The then_with method is used only if the previous comparison
returned Equal. The closure is evaluated lazily, so the later
comparisons are skipped when the team already decides.
players.sort_by_key(|p| (Reverse(p.score), p.name));
Tuples compare element by element, so a tuple key expresses the same idea more briefly. Jana and Marek both have 51 points and are ordered by name.
$ cargo run -q blue 51 Jana blue 37 Adam red 51 Marek red 42 Lucia red 37 Ivan 51 Jana blue 51 Marek red 42 Lucia red 37 Adam blue 37 Ivan red
Deriving Ord
A struct or enum can derive Ord, which makes plain
sort work on it.
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
enum Priority {
Critical,
High,
Normal,
Low,
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
struct Ticket {
priority: Priority,
id: u32,
title: &'static str,
}
fn main() {
let mut tickets = vec![
Ticket { priority: Priority::Low, id: 4, title: "typo in footer" },
Ticket { priority: Priority::Critical, id: 7, title: "site down" },
Ticket { priority: Priority::Normal, id: 2, title: "slow search" },
Ticket { priority: Priority::Critical, id: 3, title: "data loss" },
Ticket { priority: Priority::High, id: 5, title: "login fails" },
];
tickets.sort();
for t in &tickets {
println!("{:<9} #{} {}", format!("{:?}", t.priority), t.id, t.title);
}
println!("{}", Priority::High < Priority::Low);
println!("{:?}", tickets.iter().map(|t| t.priority).max());
}
The derived ordering of an enum follows the order of the variants in the declaration.
enum Priority {
Critical,
High,
Normal,
Low,
}
Critical is the smallest value, so critical tickets are
sorted first. Consequently max returns Low.
struct Ticket {
priority: Priority,
id: u32,
title: &'static str,
}
For structs, the derived ordering compares the fields from top to bottom. Tickets are sorted by priority first and by ID second. Reordering the fields changes the sort order.
$ cargo run -q Critical #3 data loss Critical #7 site down High #5 login fails Normal #2 slow search Low #4 typo in footer true Some(Low)
Implementing Ord
When the derived ordering is not suitable, we implement Ord
by hand.
use std::cmp::Ordering;
#[derive(Debug, PartialEq, Eq)]
struct Version {
text: String,
}
impl Version {
fn parts(&self) -> Vec<u32> {
self.text.split('.').map(|p| p.parse().unwrap_or(0)).collect()
}
}
impl Ord for Version {
fn cmp(&self, other: &Self) -> Ordering {
self.parts().cmp(&other.parts())
}
}
impl PartialOrd for Version {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
fn main() {
let input = ["1.10.0", "1.2.3", "1.9", "2.0.1", "1.10", "0.9.12"];
let mut as_text = input.to_vec();
as_text.sort();
println!("{as_text:?}");
let mut versions: Vec<Version> = input.iter().map(|s| Version { text: s.to_string() }).collect();
versions.sort();
let sorted: Vec<&str> = versions.iter().map(|v| v.text.as_str()).collect();
println!("{sorted:?}");
}
Version strings sorted as text put 1.10 before
1.2.3, because the character 1 is smaller than
2.
impl Ord for Version {
fn cmp(&self, other: &Self) -> Ordering {
self.parts().cmp(&other.parts())
}
}
We split each version into numbers and compare the vectors. Vectors are
compared element by element, and a shorter vector that is a prefix of a
longer one is smaller, so 1.10 comes before
1.10.0.
impl PartialOrd for Version {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
Ord requires PartialOrd, Eq, and
PartialEq. The PartialOrd implementation must
agree with Ord, so it simply delegates to it. Note that the
derived PartialEq compares the text, so 1.10 and
1.10.0 are not equal even though they are ordered as
neighbours; for a strict implementation, equality should be based on the
same parts.
$ cargo run -q ["0.9.12", "1.10", "1.10.0", "1.2.3", "1.9", "2.0.1"] ["0.9.12", "1.2.3", "1.9", "1.10", "1.10.0", "2.0.1"]
Natural sort order
File names with numbers sort badly as plain strings. A key that separates the text from the number gives the natural order.
fn split_num(s: &str) -> (&str, u64) {
let pos = s.find(|c: char| c.is_ascii_digit()).unwrap_or(s.len());
let (head, tail) = s.split_at(pos);
let num = tail.trim_end_matches(".txt").parse().unwrap_or(0);
(head, num)
}
fn main() {
let mut files = vec!["file10.txt", "file2.txt", "file1.txt", "doc3.txt", "file20.txt", "doc12.txt"];
files.sort();
println!("{files:?}");
files.sort_by_key(|f| split_num(f));
println!("{files:?}");
}
The split_num function splits a name such as
file10.txt into ("file", 10).
let pos = s.find(|c: char| c.is_ascii_digit()).unwrap_or(s.len()); let (head, tail) = s.split_at(pos);
We find the first digit and split the string there. The number is parsed from the rest without the extension.
files.sort_by_key(|f| split_num(f));
The tuple key compares the prefixes as text and the numbers as numbers,
so file2 now comes before file10. The key
borrows from the element, which works here because the elements are
&str references that outlive the sort.
$ cargo run -q ["doc12.txt", "doc3.txt", "file1.txt", "file10.txt", "file2.txt", "file20.txt"] ["doc3.txt", "doc12.txt", "file1.txt", "file2.txt", "file10.txt", "file20.txt"]
Borrowed keys
A key that borrows from the element itself cannot be returned from the
sort_by_key closure.
struct City {
name: String,
population: u32,
}
fn main() {
let mut cities = vec![
City { name: String::from("Košice"), population: 228_000 },
City { name: String::from("Bratislava"), population: 475_000 },
];
cities.sort_by_key(|c| &c.name);
for c in &cities {
println!("{} {}", c.name, c.population);
}
}
We try to sort cities by name without cloning the string.
cities.sort_by_key(|c| &c.name);
The signature of sort_by_key requires the key type to be
independent of the borrow of the element, but &c.name
lives only as long as that borrow. The compiler rejects the closure.
$ cargo run -q error: lifetime may not live long enough --> src/main.rs:12:28 | 12 | cities.sort_by_key(|c| &c.name); | -- ^^^^^^^ returning this value requires that `'1` must outlive `'2` | || | |return type of closure is &'2 std::string::String | has type `&'1 City`
Sorting with borrowed fields
The fix is sort_by, which compares two references directly.
struct City {
name: String,
population: u32,
}
fn main() {
let mut cities = vec![
City { name: String::from("Košice"), population: 228_000 },
City { name: String::from("Bratislava"), population: 475_000 },
City { name: String::from("Žilina"), population: 80_000 },
City { name: String::from("Banská Bystrica"), population: 74_000 },
];
cities.sort_by(|a, b| a.name.cmp(&b.name));
for c in &cities {
println!("{:<16} {:>7}", c.name, c.population);
}
println!();
cities.sort_by_key(|c| c.population);
for c in &cities {
println!("{:<16} {:>7}", c.name, c.population);
}
}
Inside the comparator, both names are borrowed only for the comparison.
cities.sort_by(|a, b| a.name.cmp(&b.name));
No string is cloned. Another option is
sort_by_key(|c| c.name.clone()), which allocates on every
comparison.
cities.sort_by_key(|c| c.population);
Copy values such as numbers can be returned from the key function
without any problem. Note that the names are sorted by bytes:
Ž comes after the ASCII letters. Locale-aware collation needs
a crate such as icu_collator.
$ cargo run -q Banská Bystrica 74000 Bratislava 475000 Košice 228000 Žilina 80000 Banská Bystrica 74000 Žilina 80000 Košice 228000 Bratislava 475000
Partial sorting and selection
Sometimes we need to sort only part of the data, or we only need the element that would be at a certain position.
fn main() {
let mut v = vec![9, 4, 7, 1, 8, 2, 6, 3, 5];
v[3..].sort();
println!("tail sorted: {v:?}");
let mut data: Vec<u32> = (1..=25).map(|i| i * 37 % 101).collect();
println!("data: {data:?}");
let mid = data.len() / 2;
let (_, median, _) = data.select_nth_unstable(mid);
println!("median: {median}");
println!("after select: {data:?}");
let mut scores = [55, 91, 78, 64, 99, 70, 85, 42];
let k = 3;
scores.select_nth_unstable_by(k - 1, |a, b| b.cmp(a));
let mut top = scores[..k].to_vec();
top.sort_unstable_by(|a, b| b.cmp(a));
println!("top {k}: {top:?}");
println!("{} {}", v.is_sorted(), top.is_sorted_by(|a, b| a >= b));
}
Since sorting works on slices, we can sort a range of a vector.
v[3..].sort();
Only the elements from index 3 on are sorted; the first three stay where they are.
let (_, median, _) = data.select_nth_unstable(mid);
The select_nth_unstable method moves the element that belongs
at index mid to that place. All smaller elements end up before
it and all larger after it, but neither side is sorted. This takes linear
time on average, faster than a full sort. It returns the left part, the
element, and the right part.
scores.select_nth_unstable_by(k - 1, |a, b| b.cmp(a)); let mut top = scores[..k].to_vec();
With a reversed comparator, the first k elements are the
k largest. We sort just these three.
println!("{} {}", v.is_sorted(), top.is_sorted_by(|a, b| a >= b));
The is_sorted and is_sorted_by methods check the
order without changing anything.
$ cargo run -q tail sorted: [9, 4, 7, 1, 2, 3, 5, 6, 8] data: [37, 74, 10, 47, 84, 20, 57, 94, 30, 67, 3, 40, 77, 13, 50, 87, 23, 60, 97, 33, 70, 6, 43, 80, 16] median: 47 after select: [16, 10, 20, 30, 3, 13, 23, 33, 6, 37, 40, 43, 47, 50, 57, 60, 67, 70, 74, 77, 80, 84, 87, 94, 97] top 3: [99, 91, 85] false true
Sorting, deduplicating, and searching
A sorted vector supports removing duplicates and fast searching.
fn main() {
let mut tags = vec!["rust", "web", "cli", "rust", "async", "web", "rust"];
tags.sort_unstable();
println!("{tags:?}");
tags.dedup();
println!("{tags:?}");
match tags.binary_search(&"db") {
Ok(i) => println!("found at {i}"),
Err(i) => {
tags.insert(i, "db");
println!("inserted at {i}: {tags:?}");
}
}
}
The dedup method removes consecutive equal elements. After
sorting, all equal elements are adjacent, so every duplicate is removed.
match tags.binary_search(&"db") {
Ok(i) => println!("found at {i}"),
Err(i) => {
tags.insert(i, "db");
The binary_search method needs sorted input. If the element
is missing, the Err variant holds the index where it can be
inserted so that the vector stays sorted.
$ cargo run -q ["async", "cli", "rust", "rust", "rust", "web", "web"] ["async", "cli", "rust", "web"] inserted at 2: ["async", "cli", "db", "rust", "web"]
Performance
The last example compares stable and unstable sorting on ten million numbers.
use std::time::Instant;
fn main() {
let n = 10_000_000u64;
let data: Vec<u64> = (0..n).map(|i| i.wrapping_mul(0x9E37_79B9_7F4A_7C15) % 1000).collect();
let mut a = data.clone();
let t = Instant::now();
a.sort();
println!("sort: {:?}", t.elapsed());
let mut b = data.clone();
let t = Instant::now();
b.sort_unstable();
println!("sort_unstable: {:?}", t.elapsed());
let t = Instant::now();
a.sort();
println!("sort (sorted): {:?}", t.elapsed());
println!("equal: {}", a == b);
}
The numbers are pseudo-random values between 0 and 999, so there are many duplicates.
a.sort(); b.sort_unstable();
The stable sort is a merge sort variant (driftsort) that needs a buffer of up to half the input. The unstable sort is a quicksort variant (ipnsort) that works in place.
let t = Instant::now(); a.sort();
Both algorithms detect already sorted runs, so sorting sorted data is very fast.
On an Intel Core i5-1135G7 in release mode, the unstable sort was more than twice as fast. The timings vary between runs.
$ cargo run -q --release sort: 173.534614ms sort_unstable: 78.249409ms sort (sorted): 6.368766ms equal: true
Source
In this article we have sorted data in Rust. Ordered collections are covered in Rust HashSet and BTreeMap, and more slice methods in Rust vectors and Rust slices.
Author
List all Rust tutorials.