Skip to content

Vec::dedup_by_key

Vec methods · Collections

Level: reference · for working programmers

One line: dedup comparing a derived key rather than the whole element.

pub fn dedup_by_key<F, K>(&mut self, key: F)
where
    F: FnMut(&mut T) -> K,
    K: PartialEq,

Stable since 1.16.0.

Collapses consecutive runs whose key is equal, keeping the first element of each run. v.dedup_by_key(|r| r.id) is the readable way to say "one row per id" over data already grouped by id.

Consecutive, still: sort by the same key first if the runs are not already together.

The closure takes &mut T, so it may normalise on the way past — lowercasing a name and deduping on the result in one call.

The key type needs only PartialEq — not Ord, not Hash — so a key can be a tuple, a bool, or any small struct that derives PartialEq.

Equivalent to dedup_by(|a, b| key(a) == key(b)), and clearer whenever a key function exists.

Example

vec_dedup_by_key.rs in full — pasted here by tools/run_examples.py from the file CI compiles and runs.

fn main() {
    // Collapse consecutive runs that map to the same key.
    let mut v = vec![10, 16, 20, 21, 30];
    v.dedup_by_key(|n| *n / 10);
    println!("{v:?}");

    // The element kept from each run is the FIRST one.
    #[derive(Debug)]
    struct Row { id: u8, note: &'static str }
    let mut rows = vec![
        Row { id: 1, note: "first" },
        Row { id: 1, note: "second" },
        Row { id: 2, note: "third" },
    ];
    rows.dedup_by_key(|r| r.id);
    println!("{:?}", rows.iter().map(|r| (r.id, r.note)).collect::<Vec<_>>());

    // Consecutive, still. Sort by the key first if the runs are not grouped.
    let mut v = vec![("b", 1), ("a", 2), ("b", 3)];
    v.dedup_by_key(|p| p.0);
    println!("ungrouped: {v:?}");
    let mut v = vec![("b", 1), ("a", 2), ("b", 3)];
    v.sort_by_key(|p| p.0);
    v.dedup_by_key(|p| p.0);
    println!("sorted first: {v:?}");

    // The closure gets &mut T, so it may normalise on the way past.
    let mut names = vec![String::from("Ada"), String::from("ADA"), String::from("Ben")];
    names.dedup_by_key(|s| { *s = s.to_lowercase(); s.clone() });
    println!("{names:?}");

    // The key type only needs PartialEq, not Ord or Hash.
    #[derive(PartialEq)]
    struct Key(bool);
    let mut flags = vec![0, 2, 4, 5, 7, 8];
    flags.dedup_by_key(|n| Key(*n % 2 == 0));
    println!("runs of even/odd: {flags:?}");
}

Verified output of vec_dedup_by_key.rs — regenerated by tools/run_examples.py, never hand-typed.

[10, 20, 30]
[(1, "first"), (2, "third")]
ungrouped: [("b", 1), ("a", 2), ("b", 3)]
sorted first: [("a", 2), ("b", 1)]
["ada", "ben"]
runs of even/odd: [0, 5, 8]

See also

Vec::dedup_by_key in the standard library ↗