1

What's the most idiomatic way to get the Rust vec equivalent of this Python code?

import numpy as np
a = np.arange(5)
a_diff = np.diff(a) # this is the thing I'm trying to emulate in Rust
print(a_diff) # [1 1 1 1]

I can figure out multiple unsatisfactory ways of doing this, but I figure there's got to be a clean one-liner approach using iter(), right?

let a: Vec<f64> = (0..5).collect::<Vec<i64>>().iter().map(|x| *x as f64).collect();
let a_diff = ???
Chad
  • 1,434
  • 1
  • 15
  • 30
  • 1
    You want the difference of each element from the previous one? – PitaJ Jan 19 '23 at 21:00
  • 3
    nit: `.collect::>().iter()` is redundant in your code. Range syntax is an iterator, so you can just do `(0..5).map(|x| x as f64).collect()` – PitaJ Jan 19 '23 at 21:27

2 Answers2

4

With stock Rust I'd use windows:

fn main() {
    let a: Vec<f64> = (0..5).map(|x| x as f64).collect();
    let a_diff: Vec<f64> = a
        .windows(2)
        .map(|vs| {
            let [x, y] = vs else { unreachable!() };
            y - x
        })
        .collect();
    dbg!(a_diff);
}

(I also removed the needless collection into a Vec<i64>.)

When using nightly that can be shortened to this:

#![feature(array_windows)]
fn main() {
    let a: Vec<f64> = (0..5).map(|x| x as f64).collect();
    let a_diff: Vec<f64> = a.array_windows().map(|[x, y]| y - x).collect();
    dbg!(a_diff);
}
cafce25
  • 15,907
  • 4
  • 25
  • 31
3

If you're dealing with Vec, you can use windows:

let a: Vec<f64> = (0..5).map(|x| x as f64).collect();
let a_diff: Vec<f64> = a.windows(2).map(|s| s[1] - s[0]).collect();

If you want to do it using only iterators, you can use scan, but it's more involved:

let mut a = (0..5).map(|x| x as f64);
let a_diff: Vec<f64> = if let Some(first) = a.next() {
    a.scan(first, |prev, x| {
        let out = x - *prev;
        *prev = x;
        Some(out)
    }).collect()
} else { vec![] };

Or you can use tuple_windows from the itertools crate:

use itertools::Itertools;

let a = (0..5).map(|x| x as f64);
let a_diff: Vec<f64> = a.tuple_windows().map(|(a, b)| b - a).collect();
PitaJ
  • 12,969
  • 6
  • 36
  • 55