Reputation: 9753
I have the following function, which takes a vector as argument and returns a vector of its pairs of elements:
fn to_pairs(flat: Vec<u64>) -> Vec<(u64, u64)> {
assert!(flat.len() % 2 == 0);
let mut pairs = Vec::new();
pairs.reserve(flat.len() / 2);
for pair in flat.chunks(2) {
assert!(pair.len() == 2);
pairs.push((pair.get(0).unwrap().clone(), pair.get(1).unwrap().clone()));
}
pairs
}
I want consume the vector flat
so I don't have to clone its elements when constructing the pair.
Is it possible to do so without reimplementing a variation of Vec::chunks()
myself?
Upvotes: 2
Views: 186
Reputation: 430673
I want consume the vector
flat
so I don't have to clone its elements when constructing the pair.
Convert the input Vec
into an iterator, then take two things from the iterator at a time. Essentially, you want the same thing as processing a Range
(an iterator) in chunks:
fn to_pairs<T>(flat: Vec<T>) -> Vec<(T, T)> {
let len = flat.len();
assert!(len % 2 == 0);
let mut pairs = Vec::with_capacity(len / 2);
let mut input = flat.into_iter().peekable();
while input.peek().is_some() {
match (input.next(), input.next()) {
(Some(a), Some(b)) => pairs.push((a, b)),
_ => unreachable!("Cannot have an odd number of values"),
}
}
pairs
}
fn main() {
assert_eq!(vec![(1,2), (3,4)], to_pairs(vec![1,2,3,4]));
assert_eq!(vec![(true,true), (false,false)], to_pairs(vec![true,true,false,false]));
}
The assert!(len % 2 == 0);
is quite important here, as Iterator
makes no guarantees about what happens after the first time next
returns None
. Since we call next
twice without checking the first value, we could be triggering that case. In other cases, you'd want to use fuse
.
As pointed out by Kha, you could simplify the while
loop a bit:
let mut input = flat.into_iter();
while let (Some(a), Some(b)) = (input.next(), input.next()) {
pairs.push((a, b));
}
Upvotes: 1