How to fold vector of vector in rust?
I have a vector of vector like the following.
let m: Vec<Vec<u64>> = vec![
vec![1, 2, 3, 4, 5],
vec![1, 2, 3, 4, 5],
vec![1, 2, 3, 4, 5],
vec![1, 2, 3, 4, 5],
vec![1, 2, 3, 4, 5]
];
And add
function that is intended add each element of two vector.
fn add(xs: &Vec<u64>, ys: &Vec<u64>) -> Vec<u64> {
xs.iter().zip(ys.iter()).map(|(x, y)| x + y).collect()
}
Now, I want to fold
the vector of vector m
.
What I tried is:
let s: Vec<u64> = m[1..]
.iter()
.fold(m[0], |acc, xs| add(&acc, xs));
But this code doesn't pass the compiler.
|
16 | .fold(m[0], |acc, xs| add(&acc, xs));
| ^^^^ move occurs because value has type `Vec<u64>`, which does not implement the `Copy` trait
I tried prepend &
but the compiler still rejects:
|
16 | .fold(&m[0], |acc, xs| add(&acc, xs));
| ^^^^^ expected struct `Vec`, found `&Vec<u64>`
|
= note: expected struct `Vec<u64>`
found reference `&Vec<u64>`
help: consider removing the borrow
|
16 - .fold(&m[0], |acc, xs| add(&acc, xs));
16 + .fold(m[0], |acc, xs| add(&acc, xs));
|
I think the signature of add
function is correct as it doesn't want to take ownership of the arguments vectors, and it returns a new vector so the ownership should be passed to the caller.
Actually, I tried every possible combinations (add/remove &
from the function, etc.), but couldn't make the code pass the compiler.
Can you let me know what I missed, what is wrong with the above code? Thanks.
Solution 1:
The first argument of fold
must be the same type as its output. Therefore your suggestion of passing & m[0]
, which has type & Vec<u64>
, won't work, since you want the fold to return Vec<u64>
(notice value vs borrowed value). And using m[0]
(without borrowing) won't work because you would be trying to move from a vector that is later used (in the iteration itself).
One option could be to start with m[0].clone()
as the initial value. That does involve a cloning, obviously, but you need to allocate your output somehow anyway, so you can't do better. This works:
let s: Vec<u64> = m[1..].iter().fold(m[0].clone(), |acc, xs| add(& acc, xs));
Unrelatedly: I suggest you change add
to have the more general signature fn add(xs: & [u64], ys: & [u64]) -> Vec<u64>
. You can still use it the way you are (because & Vec<u64>
coerces into & [u64]
), but it's more general, because other types coerce into & [u64]
too.