Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Idiomatic and efficient way to get a vector filter and its complement

Suppose I have a vector, a filter over it, and I want to deconstruct it into two vectors: A filtered vector, and its complement. I see two ways to do this. The first is with a for loop:

let vct: Vec<u32> = vec![1, 3, 4, 7, 9, 10, 12];
let filter = |x| x % 3 == 0;

let mut filtered: Vec<u32> = Vec::new();
let mut complement: Vec<u32> = Vec::new();
for v in vct {
    if filter(v) {
        filtered.push(v);
    } else {
        complement.push(v);
    }
}

println!("{:?}", filtered);   //[3, 9, 12]
println!("{:?}", complement); //[1, 4, 7, 10]

This seems efficient, but unnecessarily verbose (and adds unnecessary mutability to the vectors). The other one is a naive way with iterators:

let vct: Vec<u32> = vec![1, 3, 4, 7, 9, 10, 12];
let filter = |x:&&u32| *x % 3 == 0;

let filtered: Vec<u32> = vct.iter().filter(filter).cloned().collect();
let complement: Vec<u32> = vct.into_iter().filter(|x| !filter(&x)).collect();

println!("{:?}", filtered);   //[3, 9, 12]
println!("{:?}", complement); //[1, 4, 7, 10]

Which has a clearer intent and is less verbose (save the filter definition/usage, which is a bit uglier), but iterates twice over the array, which seems unnecessary.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Both of these solutions seem sub-optimal.

Is there an idiomatic and efficient way (without re-iteration) to split a vector into a filter and its complement?

>Solution :

The operation you are attempting to do is called partitioning. You can use Iterator.partition():

let vct: Vec<u32> = vec![1, 3, 4, 7, 9, 10, 12];
let filter: fn(u32) -> bool = |x| x % 3 == 0;

let (filtered, complement): (Vec<u32>, Vec<u32>) = vct.iter().partition(|x| filter(**x));

assert_eq!(&[3, 9, 12], filtered.as_slice());
assert_eq!(&[1, 4, 7, 10], complement.as_slice());

Playground

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading