Need the longest string in a Vec? Don’t sort the whole list to grab the last element — max_by_key walks once, allocates nothing, and returns it directly.
The wasteful way
You want the longest word from a list. The first instinct is often to sort and pick:
1
2
3
4
5
6
7
| let mut words = vec!["fig", "apple", "kiwi", "blackberry", "pear"];
// Sort the full vec by length, then grab the last element.
words.sort_by_key(|w| w.len());
let longest = words.last().unwrap();
assert_eq!(*longest, "blackberry");
|
That’s O(n log n) work — and a side effect, since your Vec is now reordered — just to answer “which one is biggest?”.
Enter max_by_key
max_by_key walks the iterator once, tracks the running maximum, and hands you the element it picked:
1
2
3
4
5
| let words = vec!["fig", "apple", "kiwi", "blackberry", "pear"];
let longest = words.iter().max_by_key(|w| w.len()).unwrap();
assert_eq!(*longest, "blackberry");
|
O(n), no allocation, no mutation. The original Vec is untouched and you get a &&str back without cloning anything.
Same energy: min_by_key
The mirror method is just as useful — find the shortest word in one pass:
1
2
3
4
5
| let words = vec!["fig", "apple", "kiwi", "blackberry", "pear"];
let shortest = words.iter().min_by_key(|w| w.len()).unwrap();
assert_eq!(*shortest, "fig");
|
Picking by computed value
The closure can do real work — compute distance, score, age — anything that returns something Ord:
1
2
3
4
5
6
7
8
9
10
11
| struct Player { name: &'static str, score: u32 }
let roster = [
Player { name: "Ferris", score: 80 },
Player { name: "Corro", score: 95 },
Player { name: "Crusty", score: 60 },
];
let top = roster.iter().max_by_key(|p| p.score).unwrap();
assert_eq!(top.name, "Corro");
|
No need to sort, no need to implement Ord on the struct — just point at the field that decides.
Tiebreaks: last one wins
When two elements share the same key, max_by_key returns the last one and min_by_key returns the first:
1
2
3
4
5
6
7
| let v = vec![(1, 'a'), (3, 'b'), (3, 'c'), (2, 'd')];
let max = v.iter().max_by_key(|(k, _)| *k).unwrap();
let min = v.iter().min_by_key(|(k, _)| *k).unwrap();
assert_eq!(*max, (3, 'c')); // last 3
assert_eq!(*min, (1, 'a')); // first 1
|
Worth knowing if your data has duplicates — pick the iteration direction so the right element wins.
When to reach for it
If you catch yourself sorting and then grabbing first(), last(), or [0], stop. min_by_key and max_by_key are the targeted tools: one pass, zero allocations, and the result type is exactly the element you wanted.