I have a List
of Coordinate
s that each contain an x and y position. The class has a distanceTo(Coordinate coord)
method, which returns the distance from the object's x/y position to that of coord
.
Now I want to calculate the length of a path that is represented as List<Coordinate> path
and I'm pretty sure that there must be a clever way to do this with streams. Probably via reduce
, collect
or mapToDouble
... I tried to find a solution but was unable to. The best I could find was this similar problem: How to get length of path using java 8 streams
But the answer there, to write a whole new class only for this one seems overkill for my use case.
Is there an elegant solution for this problem that doesn't involve creating a whole new class for distance?
Here is a simple code example of what I'm trying to do:
import java.util.List;
public class Main {
public static void main(String[] args) {
Coordinate c1 = new Coordinate(0, 0);
Coordinate c2 = new Coordinate(0, 1);
Coordinate c3 = new Coordinate(1, 1);
Coordinate c4 = new Coordinate(1, 2);
List<Coordinate> path = List.of(c1, c2, c3, c4);
// Primitive solution I use currently
double pathLength = 0;
for (int i = 0; i < path.size() - 1; i++) {
pathLength += path.get(i).distanceTo(path.get(i + 1));
}
// Using Steams
}
public static class Coordinate {
private final int x;
private final int y;
public Coordinate(int x, int y) {
this.x = x;
this.y = y;
}
public double distanceTo(Coordinate coord) {
return Math.hypot(x - coord.x, y - coord.y);
}
}
}
Streams are very useful but not always appropriate for every situation - for
loops may be far easier. However it is possible to do this calculation with a stream reduce
operation without need for extra holder class of intermediate results:
double[] dist = new double[1];
path.stream().reduce((a,b) -> { dist[0] += a.distanceTo(b); return b; });
The accumulator function for this reduce adds each distance to the local array variable and is returning the second coordinate value b
. That means the reduce gets called with each pairing of coordinates in the list sequence order, as mentioned by the javadoc for reduce.
Obviously you cannot use stream parallel()
here as the pairings passed to accumulator won't be in list sequence order.