有没有办法合并以下两种语句?
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
是List
,有很多DataPoints
现在,我想为列表中的每个DataPoint
创建DataPoints
,并使用相同的Id
。 DataPoint
应该具有相同x and y values
的数据点Id
的平均值。
使用来自Beginning的两个Statemantes,我必须从两个地图中手动创建DataPoints
。
有没有办法直接在流中创建它们?
答案 0 :(得分:5)
一般的解决方案是使用一个收集器,它可以将两个收集器组合在一起进行处理。遗憾的是,标准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()+']';
}
}
此变体的使用方法与第一种变体的使用方式相同。