我有一个坐标列表,每个坐标都包含 x 和 y 位置。该类还提供了 distanceTo(Coordinate coord) 方法,该方法返回坐标对象的 xy 位置到坐标坐标的距离。
现在我想计算表示为列表路径的路径的长度,并且我非常确定必须有一种巧妙的方法来使用流来执行此操作。可能通过reduce、collect或mapToDouble...我试图找到解决方案但无法找到。我能找到的最好的是这个类似的问题:How to get length of path using java 8 Streams
但是答案是,仅为这个类编写一个全新的类对于我的用例来说似乎有点过分了。
是否有一个优雅的解决方案来解决这个问题,而不涉及为距离创建一个全新的类?
任何帮助将不胜感激。谢谢你。
这是我想要做的一个简单的代码示例:
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);
}
}
}
流非常有用,但并不总是适合所有情况 -
for
循环可能要容易得多。然而,可以使用流 reduce
操作来完成此计算,而不需要中间结果的额外持有者类:
double[] dist = new double[1];
path.stream().reduce((a,b) -> { dist[0] += a.distanceTo(b); return b; });
此reduce 的累加器函数将每个距离添加到局部数组变量中,并返回第二个坐标值
b
。这意味着按照列表序列顺序中的每对坐标都会调用reduce,如reduce的javadoc中提到的。
显然你不能在这里使用流parallel()
,因为传递给累加器的配对不会按列表顺序排列。
class PathDistance {
Coordinate start;
Coordinate end;
double distance = 0.0;
void addToPath(Coordinate newEnd) {
if (start == null) {
start = newEnd;
} else {
distance += end.distanceTo(newEnd);
}
end = newEnd;
}
PathDistance combine(PathDistance next) {
if (start == null) {
this.start = next.start;
this.end = next.end;
this.distance = next.distance;
} else if (next.start != null) {
distance += end.distanceTo(next.start) + next.distance;
end = next.end;
}
return this;
}
}
Collector<Coordinate, PathDistance, Double> collector = Collector.of(
PathDistance::new, PathDistance::addToPath,
PathDistance::combine, s -> s.distance);
return path.stream().collect(collector);
该解决方案的一个优点是它是完全可并行的,这对于非常大的数据集可能是有益的。尽管我怀疑对于这个特定的用例,数据集将足够小,因此 for 循环可能是最合理的方法。