I have an input vector which contains numbers. In an output vector, I need to get a sequence of partial products but in right-to-left order. The last element of the output m
Your prod variable is carrying state across from one item to the next, which is not what a mapping does. Mappings operate on each element independently, which makes them easily parallelized and easier to reason about. The result you're asking for is to be precise a right scan (a reversed case of a prefix sum), but I'm not sure there are convenient methods to collect from the right (probably the easiest mutable way would be using VecDeque::push_front). This led me to perform the operation in two passes for my first version:
fn main() {
let input: Vec = vec![2, 3, 4];
let initprod = 1;
let prev: Vec = input
.iter()
.rev()
.scan(initprod, |prod, &v| {
*prod *= v;
Some(*prod)
}).collect();
let p: Vec = prev.into_iter().rev().collect();
println!("{:?}", p);
}
Note that initprod is immutable; prod carries the state. Using into_iter also means prev is consumed. We could use vec.reverse as shown by mcarton, but then we need to have a mutable variable. Scans can be parallelized, but to a lesser degree than maps. See e.g. discussion on adding them to Rayon. One might also consider if a ExactSizeIterator should allow reverse collection into an ordinary vector, but the standard library scan method breaks the known size using Option (which by the next convention turns it into a take-while-scan).
Here's a fewer copy variant using a preallocated VecDeque to collect from the right. I used an extra scope to restrict the mutability. It also requires Rust 1.21 or later to use for_each. There's unnecessary overhead in tracking the number of items and ring buffer structure, but it's at least somewhat legible still.
use std::collections::VecDeque;
fn main() {
let input: Vec = vec![2,3,4];
let p = {
let mut pmut = VecDeque::with_capacity(input.len());
let initprod = 1;
input
.iter()
.rev()
.scan(initprod, |prod, &v| {
*prod *= v;
Some(*prod)
})
.for_each(|v| {
pmut.push_front(v)
});
pmut
};
println!("{:?}", p);
}
Incidentally, following the old adage about Lisp programmers knowing the value of everything and the cost of nothing, here's a Haskell version I don't really know how inefficient it is:
scanr1 (*) [2, 3, 4]