有没有办法合并以下两个语句?
Map<Integer,Double> collX = listeAllerPunkte.stream().collect(groupingBy(DataPoint::getId,
averagingDouble(DataPoint::getX)));
Map<Integer,Double> collY = listeAllerPunkte.stream().collect(groupingBy(DataPoint::getId,
averagingDouble(DataPoint::getY)));
我有一个像这样的 DataPoints
类:
public class DataPoint {
public final double x;
public final double y;
private int Id;
public DataPoint(double x, double y) {
this.x = x;
this.y = y;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
public int getId() {
return Id;
}
}
Id
包含一个介于 0-5
之间的随机值。
listeAllerPunkte
是一个包含很多DataPoints
List
现在我想为列表中具有相同 Id
的每个 DataPoints
创建一个 DataPoint
。 DataPoint
应具有具有相同 Id
的数据点的 x 和 y 值
的平均值。
对于开头的两个 Statemante,我必须从两个 map 中手动创建 DataPoints
。
有没有办法直接在流中创建它们?
最佳答案
一个通用的解决方案是使用一个收集器,它可以组合两个收集器来同时处理这两个收集器。不幸的是,标准 API 中不存在这样的收集器,但是 this answer提供此类收集器的实现。
或者,您可以通过创建自己的类来保存要点的摘要,从而为这种特定情况创建解决方案,例如
static class DataPointSummary {
long count;
double sumX, sumY;
public double getAverageX() {
return count==0? 0: sumX/count;
}
public double getAverageY() {
return count==0? 0: sumY/count;
}
public void add(DataPoint p) {
count++;
sumX+=p.getX();
sumY+=p.getY();
}
public DataPointSummary merge(DataPointSummary s) {
count+=s.count;
sumX+=s.sumX;
sumY+=s.sumY;
return this;
}
@Override
public String toString() {
return "DataPointSummary["+count+" points"
+", avg x="+getAverageX()+", avg y="+getAverageY()+']';
}
}
然后你可以像这样收集你的积分
Map<Integer,DataPointSummary> coll = listeAllerPunkte.stream().collect(
groupingBy(DataPoint::getId, Collector.of(
DataPointSummary::new, DataPointSummary::add, DataPointSummary::merge)));
请注意,我假设您的方法签名 public double getId()
是一个拼写错误,实际上 public int getId()
否则,您问题中的示例将不会不工作。
如果点的坐标具有相同的大小,则上面的摘要实现效果很好。如果您在同一组中同时遇到非常大的值和非常小的值,您可能需要一个带误差补偿算法的求和。我建议不要自己实现,而是使用 JRE 的摘要实现:
static class DataPointSummary {
final DoubleSummaryStatistics x=new DoubleSummaryStatistics();
final DoubleSummaryStatistics y=new DoubleSummaryStatistics();
public double getAverageX() {
return x.getAverage();
}
public double getAverageY() {
return y.getAverage();
}
public void add(DataPoint p) {
x.accept(p.getX());
y.accept(p.getY());
}
public DataPointSummary merge(DataPointSummary s) {
x.combine(s.x);
y.combine(s.y);
return this;
}
@Override
public String toString() {
return "DataPointSummary["+x.getCount()+" points"
+", avg x="+getAverageX()+", avg y="+getAverageY()+']';
}
}
此变体的使用方式与第一个变体相同。
关于java - 结合两个流 Java 8,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33824995/