case 1.
v1 = None
v2 = Some(vec[..])
result = Some(vec[..])
case 2.
v1 = Some(vec[..])
v2 = None
result = Some(vec[..])
case 3.
v1 = Some(vec[..])
v2 = Some(vec[..])
result = Some(vec[..])
case 4.
v1 = None
v2 = None
result = None
Is there a generalized way to implement this?
CodePudding user response:
You can take advantage of the fact that Option
s can be converted to Iterator
s and use Iterator::reduce
:
v1.into_iter()
.chain(v2.into_iter())
.reduce(|mut v1, mut v2| {
v1.append(&mut v2);
v1
})
Chaining the two Option
iterators will give us an iterator that yields either 0 (if both v1
and v2
were None
), 1 (if either v1
or v2
was None), or 2 (if both v1
and v2
were not None
) vectors. Iterator::reduce
will only "reduce" the iterator with the closure if there are 2 or more vectors in the iterator and otherwise will return the only vector, if any, in the iterator.
CodePudding user response:
You can just use a match statement representing your cases:
let result = match (v1, v2) {
(res@Some(_), None) => res,
(None, res@Some(_)) => res,
(Some(r1), Some(r2)) => Some(r1.into_iter().chain(r2).collect()),
_ => None
};
CodePudding user response:
Yes! The Option<T>
enum implements the map
method. And really a whole bunch of other iterator related methods.
The map
function takes your Option<T>
and turns it into an Option<U>
based on the closure you provide to map
. None
gets mapped to None
, and Some(el)
gets mapped to Some(closure_applied_to_el)
.
Here's how that can look like in your case:
pub fn join_vecs<T>(v1: Option<Vec<T>>, v2: Option<Vec<T>>) -> Option<Vec<T>> {
v1.map(|mut el| {el.extend(v2.into_iter().flatten()); el})
}
pub fn main() {
let v1 = vec![1,2,3];
let v1 = Some(v1);
let v2 = vec![42, 55, 69];
let v2 = Some(v2);
let res = join_vecs(v1, v2);
println!("{:?}", res);
}
Note, my version takes ownership. Fiddle around with the arguments and with iter instead if that's not what you want.