malefstro
malefstro

Reputation: 149

How to check if a collection of structs has duplicate values in the fields?

I want to extract some data from a vector from some structs in order to check if there are duplicates

#[derive(Debug)]
struct Test {
    id: i32,
    name: String
}

fn main() {
    let test1 = Test { id: 1, name: String::from("one") };
    let test2 = Test { id: 2, name: String::from("two") };
    let test3 = Test{ id: 3, name: String::from("one") };
    
    let mut small_collection = Vec::new();
    small_collection.push(test1);
    small_collection.push(test2);
    small_collection.push(test3);
    
     let uniques: Vec<String> = small_collection.iter()
        .map(|x| x.name.as_str())
        .collect();

    // let num_dups = clients.len() - uniques.len();
}

The program creates a small_collection of structs. However I want to check, after the creation of the vector, if there are duplicates in the Test.name field.

So I am trying to iterate and create a new Vector<String>. If the len() for my collections and the reduced names is the same, then there is no duplicates. In this case the value "one" appears twice.

However I am stuck, any help?

Upvotes: 0

Views: 1061

Answers (1)

pretzelhammer
pretzelhammer

Reputation: 15105

You can reduce a Vec to only unique values by calling sort and then dedup on the Vec like so:

#[derive(Debug)]
struct Test {
    id: i32,
    name: String
}

fn main() {
    let test1 = Test { id: 1, name: String::from("one") };
    let test2 = Test { id: 2, name: String::from("two") };
    let test3 = Test { id: 3, name: String::from("one") };

    let mut small_collection = Vec::new();
    small_collection.push(test1);
    small_collection.push(test2);
    small_collection.push(test3);

    let mut uniques: Vec<&str> = small_collection.iter()
        .map(|x| x.name.as_str())
        .collect();

    uniques.sort();
    uniques.dedup();

    let num_dups = small_collection.len() - uniques.len();
    assert_eq!(num_dups, 1);
}

playground

You can turn it into a one-liner by collecting into a HashSet (which does not store duplicates by default):

use std::collections::HashSet;

#[derive(Debug)]
struct Test {
    id: i32,
    name: String
}

fn main() {
    let test1 = Test { id: 1, name: String::from("one") };
    let test2 = Test { id: 2, name: String::from("two") };
    let test3 = Test { id: 3, name: String::from("one") };

    let mut small_collection = Vec::new();
    small_collection.push(test1);
    small_collection.push(test2);
    small_collection.push(test3);

    let uniques_len = small_collection.iter()
        .map(|x| x.name.as_str())
        .collect::<HashSet<&str>>()
        .len();

    let num_dups = small_collection.len() - uniques_len;
    assert_eq!(num_dups, 1);
}

playground

Upvotes: 2

Related Questions