# For loop two variables, one incrementing and other decrementing

How would you write this for loop in Rust, please?

``````        for (int l = i + 1, h = points.length - 1; l < h; l++, h--) {
int[] temp = points[l];
points[l] = points[h];
points[h] = temp;
}
``````

Do I need to use `while` or `loop`?

`points[i+1..].reverse()`

3 Likes

I mean, I can also come up with a `for` loop

``````    for (l, h) in (i + 1..)
.zip((0..points.len()).rev())
.take_while(|(l, h)| l < h)
{
points.swap(l, h)
}
``````

though most similar (looking) to the `C++` code would be a `while` loop

``````    let (mut l, mut h) = (i + 1, points.len() - 1);
while l < h {
points.swap(l, h);
l += 1;
h -= 1;
}
``````

Note that indexing in Rust has some bounds-checking overhead compared to C++; so using a library method like `reverse` will be more similar to the C++ solution performance-wise, while the manual loop might be slightly slower.

All examples in the playground:

4 Likes

To add one more alternative to the mix, for this kind of iteration pattern, you could split up the slice and iterate, reverse the right half iterator, and zip:

``````    let slice = &mut points[i + 1..];
let (left_slice, right_slice) = slice.split_at_mut(slice.len() / 2);
for (l, r) in left_slice.iter_mut().zip(right_slice.iter_mut().rev()) {
std::mem::swap(l, r);
}
``````

playground

2 Likes

You should definitely use the slice `reverse` method for this. If I'm reading your iteration bounds right, it'd be `points[(i + 1)..].reverse()`.

I went and optimized `reverse` last year (PR#90821), making sure that -- unlike the CS101 implementations -- it can optimize out all the bounds checks and that LLVM vectorizes it: https://rust.godbolt.org/z/16EaG1rT3.

8 Likes

Thank you!

For that specific case, `reverse` does the job and is pretty cool.

But what I really wanted to know was how people code that `for` loop where you initialize two variables and one is incrementing and the other is decrementing.

As usual in Rust, the answer is that you try not to deal with loops where you're manually decrementing or incrementing in the first place. If you look at your request and step back a bit, you have two things you're looping over -- so maybe you want `zip` -- and one goes in the other direction -- so maybe you want `rev`.

Combining those two observations, perhaps you'd write it something like this:

``````pub fn reverse_simple<T>(points: &mut [T]) {
let half = points.len() / 2;
let (front, back) = points.split_at_mut(half);
std::iter::zip(front, back.into_iter().rev())
.for_each(|(a, b)| std::mem::swap(a, b));
}
``````

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=70f1f72f29b733903914524d1fc888a5

...which is what steffahn wrote above 1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.