Reputation: 1010
I have a Vec<f64>
and I am trying to get say every 7th element of the vector till I run out of bounds, into another Vec<f64>
. I thought maybe I could create an index of the elements I want and then filter based on that. But I can't seem to be able to do this directly or indirectly. What I tried
let x: Vec<f64> = (1..200)
.map(|x| (x as f64)/(200 as f64))
.collect();
let y: Vec<f64> = x
.enumerate()
.filter(|&(i, _)| i % 7 == 0 )
.map(|(_, e)| e)
.collect();
But this did not work with compile error enumerate method cannot be called on Vec<f64> due to unsatisfied trait bounds
. I also found a retain method but don't see a way to apply it on the index rather than the element. A robust search of SO surprisingly did not yield anything.
Upvotes: 4
Views: 4500
Reputation: 1010
Thanks for the comments, patching everything together into a more complete answer for the community. Let's say this is the Vec: let x: Vec<f64> = (1..10).map(|x| (x as f64)/(10 as f64)).collect();
To filter the vector based on index, first we create an iterator with into_iter, then enumerate it to get index, then apply the filter, and then a map to remove the index, finally collecting it to f64 vector.
let y: Vec<f64> = x
.into_iter()
.enumerate()
.filter(|&(i, _)| i % 2 == 0 )
.map(|(_, e)| e)
.collect();
If the scope of y
is shorter than that of x
, and if you had large values in y
(say string), it might be preferable to make y
a vector of references rather than values.
let y: Vec<&f64> = x
.iter()
.enumerate()
.filter(|&(i, _)| i % 2 == 0 )
.map(|(_, e)| e)
.collect();
The key difference here is using iter()
instead of into_iter()
. This page in rust book explains it:
The iter method produces an iterator over immutable references. If we want to create an iterator that takes ownership of v1 and returns owned values, we can call
into_iter
instead ofiter
. Similarly, if we want to iterate over mutable references, we can calliter_mut
instead ofiter
.
Now, for this specific question, applying a filter to the index is probably not needed. A simpler way, as noted by Chayim below is
let y: Vec<_> = x.into_iter().step_by(2).collect();
Upvotes: 4
Reputation: 70970
Note that there is a specialized iterator adapter for that, step_by()
:
let y: Vec<_> = x.into_iter().step_by(7).collect();
Upvotes: 2
Reputation: 42282
I also found a retain method but don't see a way to apply it on the index rather than the element.
While Vec::retain
does not give you any sort of index, it takes an FnMut
and is documented to operate in-order:
This method operates in place, visiting each element exactly once in the original order, and preserves the order of the retained elements.
So you can just keep track of the index yourself:
let mut idx = 0;
x.retain(|_| {
let v = idx;
idx += 1;
v % 2 == 0
});
Or here you can specialise with a simple toggle:
let mut keep = false;
x.retain(|_| {
keep = !keep;
keep
});
Upvotes: 1