How to functionally rewrite this function?

Hello there fellow Rustceans,

I'm writing a simple function that generates a 1d random walk of length n starting from value s. The code works flawlessly but I'd like to rewrite it in a functional manner (just for fun). I thought about using fold but it returns a single value (the accumulator); instead, I need the whole vector. Could you enlight me? Thank you!

Here's the code:

fn random_walk_1d(s: i32, l: usize) -> Vec<i32> {
    // define rnd generator and picking uniformly from [-1,0,1]
    let mut rnd = rand::thread_rng();
    let gen = Uniform::from(-1..2);

    // v contains the 1d points starting from point s
    let mut v = vec![s; l];
    v[0] = s;
    for i in 1..l {
        v[i] = v[i-1] + gen.sample(&mut rnd);
    }

    v
}

I suppose you could do something like this:

fn random_walk_1d(s: i32, l: usize) -> Vec<i32> {
    // define rnd generator and picking uniformly from [-1,0,1]
    let mut rnd = rand::thread_rng();
    let gen = Uniform::from(-1..2);

    let init = (s, Vec::with_capacity(l));
    let (item, mut vec) = (0..l).fold(init, |(item, mut vec), _| {
        vec.push(item);
        (item + gen.sample(&mut rnd), vec)
    });
    vec.push(item);

    vec
}

But I don't think it's clearer than your code.

Oh, thank you! It probably isn't clearer but it is interesting indeed. I like the fact that you're bringing into the fold a tuple. Thanks for the suggestion!

scan might be clearer:

fn random_walk_id(s: i32, l: usize) -> Vec<i32> {
    let mut rnd = rand::thread_rng();
    let gen = Uniform::from(-1..2);

    (0..l)
        .scan(s, |state, _| {
            let ret = *state;
            *state += gen.sample(&mut rnd);
            Some(ret)
        })
        .collect()
}
2 Likes

I didn't know about scan at all, thank you!

fn random_walk_id(s: i32, l: usize) -> Vec<i32> {
    let mut rnd = rand::thread_rng();
    let gen = Uniform::from(-1..2);

    std::iter::successors(Some(s), |&old| Some(old + gen.sample(&mut rnd)))
        .take(l)
        .collect()
}
6 Likes

Thanks, this is really concise!

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.