Bruno
Bruno

Reputation: 6449

How to merge Vectors of Tuples without duplicates based on value in Tuple

I have two Vectors of Tuples:

let nice_nums: Vec<(u16, u32)> = vec![(1, 10), (2, 11)];
let better_nums: Vec<(u16, u32)> = vec![(3, 12), (4, 13), (1, 8)];

I would like to merge better_nums with nice_nums but better_nums should take precedence. If the first value (u16) in any of the better_nums tuples matches any first value in the nice_nums tuple then the tuple that belongs to better_nums should take precedence and be added instead of the nice_nums tuple with the same key.

I tried to do this but I am not super familiar with Rust syntax:

// merged_numbers should be [(2, 11), (3, 12), (4, 13), (1, 8)]
let merged_numbers = better_nums.iter().map(|(a, b)| {
    for (i, j) in nice_nums {
        if i == a {
            return (a, b)
        }
        return (i, j)
    }
}).cloned().collect();

Upvotes: 1

Views: 746

Answers (3)

Chayim Friedman
Chayim Friedman

Reputation: 70990

You can do that with iterators:

let nice_nums: Vec<(u16, u32)> = vec![(1, 10), (2, 11)];
let better_nums: Vec<(u16, u32)> = vec![(3, 12), (4, 13), (1, 8)];
let mut result = better_nums.clone();
result.extend(nice_nums.iter().copied().filter(|nice_tuple| {
    !better_nums
        .iter()
        .any(|better_tuple| better_tuple.0 == nice_tuple.0)
}));

Playground.

Upvotes: 1

Netwave
Netwave

Reputation: 42708

If order doesn't matter, you can use a HashMap as intermediary, inserting better_nums after to keep those values:

use std::collections::HashMap;
fn main() {
    let nice_nums: Vec<(u16, u32)> = vec![(1, 10), (2, 11)];
    let better_nums: Vec<(u16, u32)> = vec![(3, 12), (4, 13), (1, 8)];
    let result: Vec<(u16, u32)> = nice_nums
        .into_iter()
        .chain(better_nums.into_iter())
        .collect::<HashMap<u16, u32>>()
        .into_iter()
        .collect();
    
    println!("{result:?}");
}

[(2, 11), (4, 13), (3, 12), (1, 8)]

Playground

Upvotes: 2

kennyvh
kennyvh

Reputation: 2854

I don't know if this is the most idiomatic way in Rust, but this works:

fn main() {
    let nice_nums: Vec<(u16, u32)> = vec![(1, 10), (2, 11)];
    let better_nums: Vec<(u16, u32)> = vec![(3, 12), (4, 13), (1, 8)];

    // at the minimum, merged will include all of your `better_nums`
    let mut merged = better_nums.clone();
    
    nice_nums.iter().for_each(|&tup1| {
    
        // if the first element of our `nice_num` matches one of the `better_nums`
        // then do nothing. if there are no matches, add our `nice_num` to
        // `merged`
        for &tup2 in better_nums.iter() {
            if tup1.0 == tup2.0 {
                return;
            }
        }
        
        merged.push(tup1);
    });
    
    println!("{:?}", merged); // [(3, 12), (4, 13), (1, 8), (2, 11)]
}

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=f956818d09b7b9e674f054489c35ad9d

Upvotes: 1

Related Questions