Reputation: 19133
I have a vec of Points. I wish to calculate the distance between each point. To do this I would traditionally use a nested pair of loops with the inner loop staying one element in front of the outer loop. In this way I compare each pair of points just once.
for i in 0..len {
for j in i + 1..len {
// calculate distance between points i and j
}
}
I would like to know if there is a more idiomatic way to achieve this type of 'triangular' nested loop.
Below is a more complete listing showing the calculation and storage into a distances
matrix that allows me to access any distance pair.
use rand::Rng;
#[derive(Debug)]
pub struct Point {
x: i32,
y: i32,
}
impl Point {
pub fn rnd(width: i32, height: i32) -> Point {
let mut rng = rand::thread_rng();
Point {
x: rng.gen_range(0..width),
y: rng.gen_range(0..height),
}
}
}
pub fn get_distances(points: &[Point]) -> Vec<Vec<i32>> {
let len = points.len();
let mut distances: Vec<Vec<i32>> = vec![vec![0; len]; len];
for i in 0..len {
for j in i + 1..len {
let mut distance =
(points[i].x - points[j].x).pow(2) +
(points[i].y - points[j].y).pow(2);
distance = (distance as f32).sqrt() as i32;
distances[i][j] = distance;
distances[j][i] = distance;
}
}
distances
}
fn main() {
let points: Vec<Point> = (0..5).map(|_| Point::rnd(400, 600)).collect();
let distances = get_distances(&points);
println!("{:#?}", distances);
}
Upvotes: 4
Views: 915
Reputation: 42756
You could leverage iterators, although the nested for loop it is clear enough:
pub fn get_distances_iter(points: &[Point]) -> Vec<Vec<i32>> {
let len = points.len();
let mut distances: Vec<Vec<i32>> = vec![vec![0; len]; len];
for (i, j) in (0..len)
.map(|i| (i + 1..len).map(move |j| (i, j)))
.flatten()
{
let mut distance = (points[i].x - points[j].x).pow(2) + (points[i].y - points[j].y).pow(2);
distance = (distance as f32).sqrt() as i32;
distances[i][j] = distance;
distances[j][i] = distance;
}
distances
}
Upvotes: 4