Question

How to Sort a Vector in Rust

rustsorting

Question

What is the currently recommended way to sort values stored in a Rust vector?

For example, if I have a Vec<T>, what methods should I use to sort it in ascending order, descending order, or with custom sorting logic?

Short Answer

By the end of this page, you will understand how to sort a Vec in Rust using the standard library. You will learn when to use sort(), sort_unstable(), and comparator-based methods such as sort_by() and sort_by_key(), along with common mistakes and practical examples.

Concept

Sorting in Rust means rearranging the items in a collection, usually a Vec<T>, into a specific order.

The standard library provides built-in sorting methods directly on slices, and since a vector can be viewed as a mutable slice, you can call these methods on Vec<T> as well.

The most common sorting methods are:

  • sort() for a stable sort in natural order
  • sort_unstable() for a faster unstable sort when order of equal elements does not matter
  • sort_by() for custom comparison logic
  • sort_by_key() for sorting by a derived key

Why this matters:

  • Sorted data is easier to search, display, and process.
  • Many algorithms assume sorted input.
  • Real applications often sort users, products, logs, dates, or scores.

In Rust, the recommended method depends on what you need:

  • Use sort() when you want a simple ascending sort and stability matters.
  • Use sort_unstable() when you want speed and do not care about preserving the relative order of equal items.
  • Use sort_by() or sort_by_key() when sorting structs or using custom rules.

For basic values like integers or strings, sort() is usually the clearest beginner-friendly choice.

Mental Model

Think of a vector like a stack of index cards.

  • sort() reorganizes the cards from smallest to largest while keeping tied cards in their original relative order.
  • sort_unstable() also organizes the cards, but if two cards are equal, it may shuffle those tied cards around.
  • sort_by_key() is like saying, "Sort these cards by the number written in the corner," even if the full card contains more information.
  • sort_by() is like giving a human sorter a custom rulebook for how to compare any two cards.

So the main question is not just "Can Rust sort this?" but also "What comparison rule should Rust use, and do I care about stability?"

Take Quiz

Syntax and Examples

Basic ascending sort

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

Output:

[1, 2, 3, 4, 5]

sort() sorts the vector in place. That means it changes the original vector instead of creating a new one.

Descending sort

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

This uses sort_by() with a custom comparator. cmp() compares two values that implement Ord.

Sorting strings

fn main() {
    let mut words = vec!["pear", "apple", "banana"];
    words.sort();
    println!("{:?}", words);
}

Sorting structs by a field

#[derive(Debug)]
struct User {
    name: String,
    age: u32,
}

fn main() {
    let mut users = vec![
        User { name: "Ava".to_string(), age: 30 },
        User { name: "Ben".to_string(), age: 25 },
        User { name: "Cara".to_string(), age: 28 },
    ];

    users.sort_by_key(|user| user.age);

    for user in users {
        println!("{} - {}", user.name, user.age);
    }
}

sort_by_key() is often the easiest way to sort structs using one field.

Faster unstable sort

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

Use this when you do not care about preserving the order of equal elements.

Step by Step Execution

Consider this example:

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

Step by step:

  1. let mut numbers = vec![3, 1, 2];

    • A mutable vector is created.
    • The contents are [3, 1, 2].
  2. numbers.sort();

    • Rust sorts the vector in ascending order.
    • It compares elements using their natural ordering.
    • After sorting, the vector becomes [1, 2, 3].
  3. println!("{:?}", numbers);

    • The sorted vector is printed.
    • Output is [1, 2, 3].

Now a custom example:

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

Step by step:

  1. Start with [3, 1, 2].
  2. sort_by(|a, b| b.cmp(a)) reverses the normal comparison.
  3. Rust now places larger values first.
  4. Final result is [3, 2, 1].

The key idea is that sorting happens in place, so the original vector itself is changed.

Real World Use Cases

Sorting vectors is common in real Rust programs.

API and web apps

  • Sort products by price before returning JSON.
  • Sort users by signup date.
  • Sort comments by score or time.

Command-line tools

  • Sort file names alphabetically.
  • Sort log entries by timestamp.
  • Sort benchmark results from fastest to slowest.

Data processing

  • Sort numeric measurements before analysis.
  • Sort records by a key before grouping.
  • Sort words for deterministic output.

Game and simulation code

  • Sort leaderboard scores.
  • Sort entities by render order.
  • Sort events by priority.

In all of these cases, the choice between stable and unstable sort depends on whether equal items must keep their original order.

Take Quiz

Real Codebase Usage

In real projects, developers often use sorting together with common patterns.

Sorting simple values

numbers.sort();

Used for integers, strings, and other types that implement Ord.

Sorting by a struct field

users.sort_by_key(|u| u.age);

This is very common for business data such as users, orders, or events.

Reverse order

use std::cmp::Reverse;

fn main() {
    let mut numbers = vec![4, 2, 5, 1, 3];
    numbers.sort_by_key(|&n| Reverse(n));
    println!("{:?}", numbers);
}

Reverse is a clean pattern for descending sorts.

Stable sorting when ties matter

If you sort by one field and want equal values to keep their original order, use sort() or sort_by_key().

Example:

#[derive(Debug)]
struct Task {
    id: u32,
    priority: u8,
}

fn main() {
    let mut tasks = vec![
        Task { id: 1, priority: 2 },
        Task { id: 2, priority: 1 },
        Task { id: 3, priority: 2 },
    ];

    tasks.sort_by_key(|t| t.priority);

    for task in tasks {
        println!("id={} priority={}", task.id, task.priority);
    }
}

Preparing data for binary search

A common pattern is:

let mut values = vec![10, 3, 7, 1];
values.sort();
let result = values.binary_search(&7);

Binary search requires sorted data.

Common Mistakes

1. Forgetting the vector must be mutable

Broken code:

fn main() {
    let numbers = vec![3, 1, 2];
    numbers.sort();
}

Why it fails:

  • sort() modifies the vector in place.
  • The vector must be declared with mut.

Fixed code:

fn main() {
    let mut numbers = vec![3, 1, 2];
    numbers.sort();
}

2. Expecting sort() to return a new vector

Broken idea:

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

Why it fails:

  • sort() returns ().
  • It changes numbers directly.

Correct usage:

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

3. Using sort() on a type that does not implement Ord

If your struct does not have a natural ordering, sort() will not work directly.

Use sort_by() or sort_by_key() instead.

#[derive(Debug)]
struct User {
    name: String,
    age: u32,
}

fn main() {
    let mut users = vec![
        User { name: "Ava".to_string(), age: 30 },
        User { name: "Ben".to_string(), age: 25 },
    ];

    users.sort_by_key(|u| u.age);
}

4. Writing an inconsistent comparator

Broken comparator logic can produce incorrect results.

Risky example:

numbers.sort_by(|a, b| {
    if a % 2 == 0 {
        std::cmp::Ordering::Less
    } else {
        std::cmp::Ordering::Greater
    }
});

Why this is a problem:

  • A comparator must define a consistent ordering between any two elements.
  • If not, sorting behavior becomes unreliable.

5. Forgetting stability rules

If equal elements must keep their original order, do not use sort_unstable().

Use stable sorting methods instead.

Comparisons

MethodStableCustom logicBest use case
sort()YesNoSimple ascending sort for types implementing Ord
sort_unstable()NoNoFaster sort when order of equal elements does not matter
sort_by()YesYesComplex custom comparison
sort_by_key()YesYes, by keySorting structs or values by one field or derived key
sort_unstable_by()NoYesFast custom sort when stability is not needed
sort_unstable_by_key()NoYes, by keyFast key-based sorting without stability

sort() vs sort_unstable()

  • sort() preserves the relative order of equal elements.
  • sort_unstable() may reorder equal elements.
  • sort_unstable() can be a good choice for performance-sensitive code.

sort_by() vs sort_by_key()

  • Use sort_by_key() when sorting by one simple field.
  • Use sort_by() when comparison rules are more complex.

Example with sort_by_key():

users.sort_by_key(|u| u.age);

Example with sort_by():

users.sort_by(|a, b| a.name.cmp(&b.name));
Take Quiz

Cheat Sheet

// Ascending sort
vec.sort();

// Descending sort
vec.sort_by(|a, b| b.cmp(a));

// Fast unstable ascending sort
vec.sort_unstable();

// Sort by a field
vec.sort_by_key(|item| item.field);

// Sort by a field in descending order
use std::cmp::Reverse;
vec.sort_by_key(|item| Reverse(item.field));

// Custom comparison
vec.sort_by(|a, b| a.some_field.cmp(&b.some_field));

Rules to remember

  • The vector must be mutable.
  • Sorting happens in place.
  • sort() requires the element type to implement Ord.
  • Use sort_by() or sort_by_key() for custom sorting.
  • Use sort_unstable() when stability is not required.

Good defaults

  • Beginners: start with sort()
  • Sorting structs by one field: use sort_by_key()
  • Need descending order: use sort_by() or Reverse
  • Need speed and no stability: use sort_unstable()

FAQ

How do I sort a vector in ascending order in Rust?

Use sort():

let mut numbers = vec![3, 1, 2];
numbers.sort();

How do I sort a vector in descending order in Rust?

Use sort_by() with reversed comparison:

numbers.sort_by(|a, b| b.cmp(a));

What is the difference between sort() and sort_unstable() in Rust?

sort() is stable and preserves the order of equal elements. sort_unstable() may reorder equal elements but can be faster.

Can I sort a vector of structs in Rust?

Yes. A common approach is sort_by_key():

users.sort_by_key(|u| u.age);

Does sort() create a new vector?

No. It sorts the existing vector in place.

Why does Rust require mut for sorting?

Because sorting changes the order of elements inside the vector.

What trait is needed for sort()?

The element type must implement Ord.

When should I use sort_by() instead of sort_by_key()?

Use sort_by() when your comparison logic is more complex than extracting a single key.

Take Quiz

Mini Project

Description

Build a small Rust program that sorts a list of products in different ways. This demonstrates basic vector sorting, descending sorting, and sorting structs by a field, which are all common tasks in real applications.

Goal

Create a Rust program that sorts numbers and products using sort(), sort_by(), and sort_by_key().

Requirements

  1. Create a vector of integers and sort it in ascending order.
  2. Sort the same integer vector in descending order.
  3. Create a Product struct with name and price fields.
  4. Store several products in a vector.
  5. Sort the products by price and print the result.
Take Quiz

Keep learning

Related questions

View more