---
title: "18.8 Choosing a collection"
description: "A decision guide to the standard collections: when VecDeque, HashSet, and BTreeMap beat the core three, with a quick comparison table."
url: "https://learnrust.net/chapter-18/choosing-a-collection/"
last_updated: "2026-06-13"
---

# 18.8 Choosing a collection

`Vec`, `String`, and `HashMap` cover most needs, but the standard library has a few more collections worth knowing for the cases where the core three aren't the best fit. This lesson is a decision guide: brief cameos of `VecDeque`, `HashSet`, and `BTreeMap`, and a table to help you pick. You won't reach for these daily, but recognizing when one beats a `Vec` or `HashMap` is the mark of knowing the toolbox.

## VecDeque: efficient at both ends

A `Vec` is fast to push and pop at the *end*, but removing from the *front* is slow, because every remaining element has to shift down one position. When you need a queue, adding at one end and removing from the other, reach for `VecDeque` (a double-ended queue):

```rust
use std::collections::VecDeque;

fn main() {
    let mut queue = VecDeque::new();
    queue.push_back(1);
    queue.push_back(2);
    queue.push_front(0);

    println!("{:?}", queue.pop_front());   // Some(0)
    println!("{queue:?}");                 // [1, 2]
}
```

```
Some(0)
[1, 2]
```

`VecDeque` adds and removes efficiently at both ends with `push_front`/`push_back` and `pop_front`/`pop_back`. Use it for queues (first-in-first-out) and any workload that touches both ends. For a plain stack or a list you only append to, a `Vec` is simpler and just as fast.

## HashSet: membership without values

When you want a collection of *unique* items and only care whether something is present, not an associated value, use `HashSet`. It's like a `HashMap` with keys but no values:

```rust
use std::collections::HashSet;

fn main() {
    let mut seen = HashSet::new();
    seen.insert("apple");
    seen.insert("banana");
    seen.insert("apple");          // duplicate: ignored

    println!("{}", seen.len());            // 2
    println!("{}", seen.contains("apple")); // true
}
```

```
2
true
```

`HashSet` automatically discards duplicates (inserting `"apple"` twice leaves one) and answers `contains` quickly. Reach for it for "have I seen this before?", deduplication, or any set-membership question. It also offers set operations like union and intersection. If you find yourself using a `HashMap` where the values are meaningless placeholders, you wanted a `HashSet`.

## BTreeMap: a map that stays sorted

A `HashMap` is fast but stores entries in *no particular order* (you saw its unpredictable iteration order in lesson [18.6](https://learnrust.net/chapter-18/hashmap/)). When you need the keys kept *sorted*, so you can iterate in order or find ranges, use `BTreeMap` (and its set cousin `BTreeSet`):

```rust
use std::collections::BTreeMap;

fn main() {
    let mut scores = BTreeMap::new();
    scores.insert("Charlie", 3);
    scores.insert("Alice", 1);
    scores.insert("Bob", 2);

    for (name, score) in &scores {
        println!("{name}: {score}");       // always alphabetical by key
    }
}
```

```
Alice: 1
Bob: 2
Charlie: 3
```

`BTreeMap` iterates in sorted key order, always, regardless of insertion order, because it keeps its keys ordered internally (which requires the key type to be `Ord`, lesson [16.5](https://learnrust.net/chapter-16/deriving-traits/)). The tradeoff is that lookups are slightly slower than a `HashMap`'s. Choose `BTreeMap` when ordered iteration or range queries matter; choose `HashMap` when you only need fast lookup and order is irrelevant (which is more common).

## The decision table

A quick guide to the whole family:

| You want... | Reach for |
|---|---|
| A sequence, append/read at the end | `Vec<T>` |
| Growable UTF-8 text | `String` |
| Look up values by key, order doesn't matter | `HashMap<K, V>` |
| Add/remove at both ends (a queue) | `VecDeque<T>` |
| Unique items, membership testing | `HashSet<T>` |
| Key-value pairs kept in sorted order | `BTreeMap<K, V>` |
| Unique items kept in sorted order | `BTreeSet<T>` |
| Fixed number of elements, known at compile time | array `[T; N]` |

> **Best practice**
>
> Default to `Vec` and `HashMap`; they're the right answer most of the time. Switch to a specialized collection only when its specific strength matches your need: `VecDeque` for front-and-back access, `HashSet` for uniqueness, `BTreeMap`/`BTreeSet` for sorted order. The question to ask is "what operation do I do most, and which collection makes *that* operation cheap and natural?" Picking the collection that fits the access pattern is most of good data-structure choice.

## Quiz time

**Question #1**

When would you use a `VecDeque` instead of a `Vec`?

<details class="solution">
<summary>Show solution</summary>

When you need to add and remove efficiently at *both* ends, typically a queue (add at the back, remove from the front). A `Vec` is fast at the end but slow to remove from the front (everything shifts down). `VecDeque` handles both ends efficiently with `push_front`/`pop_front` and `push_back`/`pop_back`.

</details>

**Question #2**

You want to track which usernames you've already processed, with no associated data, just "seen or not." Which collection, and why?

<details class="solution">
<summary>Show solution</summary>

A `HashSet<String>` (or `HashSet<&str>`). You only care about membership and uniqueness, not an associated value, which is exactly what a set provides: it discards duplicates and answers `contains` quickly. Using a `HashMap` with placeholder values would be a sign you actually wanted a `HashSet`.

</details>

**Question #3**

What does `BTreeMap` give you that `HashMap` doesn't, and what's the tradeoff?

<details class="solution">
<summary>Show solution</summary>

`BTreeMap` keeps its keys in sorted order, so iterating yields entries in order and you can do range queries; `HashMap` has no defined order. The tradeoff is that `BTreeMap` lookups are somewhat slower than `HashMap`'s, and its key type must be `Ord`. Choose `BTreeMap` when ordered iteration matters, `HashMap` when you only need fast lookup.

</details>

That's the standard collection toolbox. The summary and a capstone quiz close the chapter, and then chapter 19 takes the iteration you've done with `for` loops throughout this chapter and reveals the powerful machinery beneath it: closures and iterators, where `map`, `filter`, and `collect` turn loops into expressive pipelines.

## Sitemap

See the full [sitemap](https://learnrust.net/sitemap.md) for all pages.
