Reputation: 6338
I have a problem understanding ownership when a higher order function is called. I am supposed to remove entries from the first vector if the elements exist in the second vector so I came up with this attempt:
fn array_diff<T: PartialEq>(a: Vec<T>, b: Vec<T>) -> Vec<T> {
a.iter()
.filter(|incoming| !b.contains(incoming))
.collect::<Vec<T>>()
}
I can't change the function signature. The .collect()
call doesn't work because all I am getting is a reference to elements in a
. While this is generic, I don't know if the result is copy
-able or clone
-able. I also probably can't dereference the elements in a
.
Is there a way to fix this piece of code without rewriting it from scratch?
Upvotes: 0
Views: 200
Reputation: 430673
Destroying the incoming allocation to create a new allocation isn't very efficient. Instead, write code that is more directly in line with the problem statement:
fn array_diff<T: PartialEq>(mut a: Vec<T>, b: Vec<T>) -> Vec<T> {
a.retain(|aa| !b.contains(aa));
a
}
Adding mut
in the signature doesn't change the signature because no one can tell that you've added it. It's the exact same as:
fn array_diff<T: PartialEq>(a: Vec<T>, b: Vec<T>) -> Vec<T> {
let mut a = a;
a.retain(|aa| !b.contains(aa));
a
}
Upvotes: 1
Reputation: 65079
For this particular test ... you can consume the vector instead of relying on references. The signature yields values and not references. As such, to pass the test you only have to use into_iter
instead:
a.into_iter() // <----------- call into_iter
.filter(|incoming| !b.contains(incoming))
.collect::<Vec<T>>()
This consumes the values and returns them out again.
Upvotes: 2