如何使用Java8流获取路径长度
我有如何使用Java8流获取路径长度,java,collections,java-8,java-stream,Java,Collections,Java 8,Java Stream,我有List,其中Vector3D是一个坐标。我想找到列表中Vector3D元素之间所有距离的总和。我想用Java8流找到它。我试图使用减少,但它帮不了我 UPD: 类Vector3D具有查找两个位置之间距离的方法双距离(Vector3D)。e、 g.我有一个带有(1,0,0)(2,0,0)(3,0,0)的列表。因此,我想找到这条路径的长度。现在是3点 如果我们使用java 7或更低版本,我们必须: public static double calcPathLength(List<Vect
List
,其中Vector3D
是一个坐标。我想找到列表中Vector3D
元素之间所有距离的总和。我想用Java8流找到它。我试图使用减少,但它帮不了我
UPD:
类Vector3D
具有查找两个位置之间距离的方法双距离(Vector3D)
。e、 g.我有一个带有(1,0,0)(2,0,0)(3,0,0)的列表。因此,我想找到这条路径的长度。现在是3点
如果我们使用java 7或更低版本,我们必须:
public static double calcPathLength(List<Vector3D> path){
double length = 0d;
for (int i=0; i< path.size()-1; i++){
length += path.get(i).distance(path.get(i+1));
}
return length;
}
publicstaticdouble-calcPathLength(列表路径){
双倍长度=0d;
对于(int i=0;i
其中一个选项是创建一些助手类,该类将记住以前使用的向量,并根据它计算它和当前向量之间的差异。这门课看起来像
class DistanceHelper {
private double sum = 0;
private Vector3D first = null;
private Vector3D last = null;
public void add(Vector3D vector3d) {
if (first == null)
first = vector3d;
if (last != null)
sum += vector3d.distance(last);
last = vector3d;
}
public void combine(DistanceHelper otherHelper) {
//add distance of path from current thread with distance of path
//from other thread
sum += otherHelper.sum;
//also add distance between paths handled by separate threads like
// when path of Thread1 is A->B and Thread2 is C->D then we need to
// include path from `B` to `C`
if (this.last!=null && otherHelper.first!=null)
sum += this.last.distance(otherHelper.first);
this.last = otherHelper.last;
}
public double getSum() {
return sum;
}
}
例如,您可以将其与combine
一起使用,而不是像这样使用reduce
double sum = list
.stream()//or parallelStream()
.collect(DistanceHelper::new, DistanceHelper::add,
DistanceHelper::combine).getSum();
您正在执行的操作称为
显示如何通过提供三个必要的功能来实现这种临时操作。但是,当所有三个函数都由专用类实现时,在实现的类中实现这些函数可能会很有用,以便于重用:
public class Distance implements Collector<Vector3D, Distance.Helper, Double> {
public static final Distance COLLECTOR = new Distance();
static final class Helper {
private double sum = 0;
private Vector3D first = null, previous = null;
}
public Set<Characteristics> characteristics() {
return Collections.emptySet();
}
public Supplier<Helper> supplier() {
return Helper::new;
}
public BiConsumer<Helper, Vector3D> accumulator() {
return (helper,vector3d)-> {
if (helper.previous != null)
helper.sum += vector3d.distance(helper.previous);
else helper.first = vector3d;
helper.previous = vector3d;
};
}
public BinaryOperator<Helper> combiner() {
return (h1,h2)-> {
h2.sum += h1.sum;
if(h1.previous!=null && h2.first!=null) {
h2.sum += h1.previous.distance(h2.first);
h2.first=h1.first;
}
return h2;
};
}
public Function<Helper, Double> finisher() {
return helper -> helper.sum;
}
}
如果我假设正确,您需要一对向量来计算它们的距离,您可能不会直接使用reduce,因为它对每个元素都有效,但是您可以计算一个距离列表,然后将该列表减少为单个结果。如何使用java 8流计算距离列表?点之间的路径(1,0,0)(2,0,0)(3,0,0)
是直线,所以它的长度不应该是2
而不是3
?我担心流在这里没有更大的用处,因为您需要一个特殊的流,为您提供两个后续元素,而不仅仅是当前元素-因此计算距离与收集器
。为什么不让DistanceHelper
实现呢?这将大大简化用例。@Holger你可能是对的,但我从来没有真正实现过这个接口(我不经常使用Java 8)我对它不是很熟悉,所以请随意发布另一个关于收集器实现示例的答案。我注意到了一个小缺陷:combine
方法没有添加两个DistanceHelper
s之间的距离。如果一个Stream
拆分为两个非空流,则拆分位置处的距离将丢失@霍尔格你们是对的,平行性使事情复杂化。若我们从不同的点开始构建两条路径,那个么我们还需要包括第一条路径的端点和第二条路径的起点之间的距离(就像在点A B C D
的情况下,当我们想要组合路径A->B
和C->D
时,我们还需要包括B->C
)。我不确定将在哪个顺序路径中进行组合,因此我怀疑可能我们最终会将第二条路径与第一条路径组合,因此我们使用第一条路径的最后一个点和最后一条路径的第一个点将为我们提供A->D
,这将是完全错误的。最安全的选择是不涉及并行性,或者以某种方式保证el的顺序将合并的元素。您可能每次都需要一个新的收集器,而不是重复使用同一个静态实例。@dkatzel:为什么?收集器是无状态的;创建多个实例毫无意义。不要将收集器
与可变的助手
容器混淆,后者将为每个m新实例化可执行的缩减,甚至为单个并行缩减多次实例化。此处显示的收集器是线程安全的,主要是因为框架的设计使其变得如此简单。合并器的工作不太好。它通过测量两个子链端点之间的距离来增加两个子链的距离。通常,您不能期望b-链要按顺序组合,因此组合器和帮助器类要复杂得多,以允许这种组合。无论如何都不会调用组合器,因为流需要顺序,否则累加器也不能很好地工作。@Mark Jeronimus:关于端点,您是对的,但是关于顺序,您是错的,如f或有序流,组合器将以保留顺序的方式使用,除非收集器
报告特征。
List<Vector3D> list;
//…
double distance=list.stream().collect(Distance.COLLECTOR);