Per title. In my case, a coordinate is let (x, y): (usize, usize)
. The start and end coordinate always have either the x or y value in common, so the range is either vertical (start.0 == end.0
) or horizontal (start.1 == end.1
). The end point should be inclusive.
My current implementation looks like
struct CoordinateRangeIterator {
stack: Vec<(usize, usize)>,
idx: usize,
}
impl CoordinateRangeIterator {
fn new(start: (usize, usize), end: (usize, usize)) -> CoordinateRangeIterator {
let stack;
if start.0 == end.0 {
let y_min;
let y_max;
if start.1 < end.1 {
y_min = start.1;
y_max = end.1;
} else {
y_min = end.1;
y_max = start.1;
}
stack = (y_min..=y_max).map(|y| (start.0, y)).collect();
} else if start.1 == end.1 {
let x_min;
let x_max;
if start.0 < end.0 {
x_min = start.0;
x_max = end.0;
} else {
x_min = end.0;
x_max = start.0;
}
stack = (x_min..=x_max).map(|x| (x, start.1)).collect();
} else {
unreachable!()
}
CoordinateRangeIterator { stack, idx: 0 }
}
}
impl Iterator for CoordinateRangeIterator {
type Item = (usize, usize);
fn next(&mut self) -> Option<Self::Item> {
if self.idx < self.stack.len() {
let item = self.stack[self.idx];
self.idx += 1;
Some(item)
} else {
None
}
}
}
This works:
assert_eq!(
CoordinateRangeIterator::new((4, 6), (7, 6))
.into_iter()
.collect::<Vec<_>>(),
vec![(4, 6), (5, 6), (6, 6), (7, 6)]
);
assert_eq!(
CoordinateRangeIterator::new((2, 5), (2, 3))
.into_iter()
.collect::<Vec<_>>(),
vec![(2, 3), (2, 4), (2, 5)]
);
My implementation returns the coordinates in "ascending" order, but that is unnecessary in my particular use case. Plus ::new()
is pretty verbose for such seemingly simple behavior.
Happy for any pointers how to improve that.