Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I reduce (fold) an iterator and keep intermediate results (such as a cumulative sum)?

Tags:

iterator

rust

I want to apply a reduction to an iterator, but I don't need just the final value, the intermediate results are important, too.

As an example, let's convert a vector of offsets to a vector of positions:

let offsets = vec![3, 2, 1, 4];
// create positions vector [3, 5, 6, 10]

My attempt at a solution uses map and a closure:

let mut acc = 0;
let positions: Vec<i32> = offsets
    .iter()
    .map(|x| {
        acc = acc + x;
        acc
    })
    .collect();

Good comment from @starblue: To do a cumulative sum, fold would be the best option. It applies a reduction and returns the last value. It doesn't return intermediate solutions though:

// basically exact code from fold example in the docs
let last_position = offsets.iter().fold(0, |acc, x| acc + x);
like image 310
lhk Avatar asked Mar 11 '19 10:03

lhk


1 Answers

I see that I should have read the docs more carefully. The function I'm looking for is called scan. Here is a cumulative sum implementation:

let offsets = vec![3, 2, 1, 4];
let positions: Vec<i32> = offsets
    .iter()
    .scan(0, |acc, &x| {
        *acc = *acc + x;
        Some(*acc)
    })
    .collect();
like image 96
lhk Avatar answered Nov 10 '22 14:11

lhk