Reputation: 1081
for x in line.x1..=line.x2 {
...
}
This doesn't work for cases where x1 > x2
, so I use this workaround:
for x in (cmp::min(line.x1, line.x2))..=(cmp::max(line.x1, line.x2)) {
...
}
This was fine until I needed to iterate through two fields in tandem:
for (x, y) in (line.x1..=line.x2).zip((line.y1..=line.y2)) {
...
}
Here my previous trick cannot work.
Is there an idiomatic way to use ranges where the start value may be greater than the end value?
Solution based on Brian's answer:
fn range_inclusive(a: usize, b: usize) -> impl Iterator<Item = usize> {
let x: Box<dyn Iterator<Item = usize>>;
if b > a {
x = Box::new(a..=b)
} else {
x = Box::new((b..=a).rev())
}
x
}
fn main() {
for i in range_inclusive(3, 1).zip(range_inclusive(1, 3)) {
println!("{:?}", i);
}
}
Upvotes: 3
Views: 2480
Reputation: 7356
I don't know if this is really better than the snippet you posted in the other comment thread, but this may also work depending on your circumstances.
Edit: the following code includes refinements from @Krish. See also his playground for it.
fn range_inclusive(a: usize, b: usize) -> impl Iterator<Item = usize> {
let x: Box<dyn Iterator<Item = usize>>;
if b > a {
x = Box::new(a..=b)
} else {
x = Box::new((b..=a).rev())
}
x
}
For posterity, here's what I had originally posted, prior to Krish's improvements.
fn get_range_iter_inclusive(a: usize, b: usize) -> impl Iterator<Item = usize> {
if b > a {
let vec: Vec<usize> = (a..=b).collect();
vec.into_iter()
} else {
let vec: Vec<usize> = (b..=a).rev().collect();
vec.into_iter()
}
}
Materializing the ranges into Vec<_>
is obviously bad for runtime performance in some cases. This was the only way I could figure out to beat the type system into submission. But I'm just learning Rust, so there could very well be a better way.
As an aside, I'm still struggling to understand why creating a descending range should not only fail, but fail silently.
Upvotes: 1
Reputation: 2561
The simplest way would be to reverse the range that you need:
for i in (0..11).rev() {
println!("{}", i);
}
will print 10 to 0 in decreasing order.
Upvotes: 4