Comparing consecutive elements of a vector to find local extrema in an idiomatic way

Viewed 34

I want to find local maxima (and minima) in a vector. So for every entry in a vector I have to check if it is larger (smaller) than the one before it AND the one after it. So I have to access 3 consecutive elements and perform 2 comparisons.

The most simple way would be this:

let v: Vec<64>; // this will hold some numeric values.

for i in 1..v.len() - 2 {
    if v[i-1] < v[i] && v[i] > v[i+1] { println!("maximum!"); }
    if v[i-1] > v[i] && v[i] < v[i+1] { println!("minimum!"); }
}

But I want to learn more about Rust and find out if there is a more idiomatic way for this. I tried doing it with an iterator, but then I still need to access 3 different locations and the iterator doesn't know its position. Also: wouldn't I need 3 iterators? I tried to circumvent this by defining 2 mutable variables which "remember" the previous two vector entries and then skipping the first 2 elements:

let v: Vec<64>; // this will hold some numeric values.

let mut two_before = v[0];
let mut one_before = v[1];
for el in v.into_iter.skip(2) {
    check_if_middle_greatest(two_before, one_before, el); // i put the comparisons into this function.
    two_before = one_before;
    one_before = *el;
}

Now this works, but it is very ugly in my opinion and doesn't really feel smart. I was wandering if this could be made more idiomatic. More "rusty".

1 Answers

You could use .windows(3) or .array_windows::<3>(), once it is stabilized.

fn print_max_min(l: i32, m: i32, r: i32) {
    if m > l && m > r {
        println!("max");
    } else if m < l && m < r {
        println!("min");
    } else {
        println!("-");
    }
}

fn main() {
    let v = [1, 2, 3, 2, 1, 2, 3];

    for el in v.windows(3) {
        print_max_min(el[0], el[1], el[2]);
    }
}
-
max
-
min
-
Related