合并两个Java 8流

4
有没有一种方法可以将以下两个语句合并?
    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 是一个包含许多 DataPointsList

现在我想为列表中每个具有相同 IdDataPoints 创建一个 DataPoint。这个 DataPoint 应该是具有相同 Id 的 Datapoints 的 x 和 y 值 的平均值。

使用开头的两个语句,我必须从这两个映射中手动创建 DataPoints。在流中是否有一种直接创建它们的方法?


3
使用这个答案,它定义了一个名为pairing的收集器。 - Tunaki
1个回答

5

一种通用解决方案是使用一个集合器来同时处理两个收集器。不幸的是,标准API中不存在这样的集合器,但此答案提供了这样一个集合器的实现。

另外,您也可以创建一个特定于此情况的解决方案,通过创建自己的类来保存点总结,例如:

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()+']';
    }
}

这个变量的使用方式和第一个变量相同。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接