java - 结合两个流 Java 8

标签 java java-8 java-stream

有没有办法合并以下两个语句?

    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 创建一个 DataPointDataPoint 应具有具有相同 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/

相关文章:

java - 流列表上的 IllegalStateException

java - 如何在 Java 中实现没有资源泄漏警告的 Stream<E>

java - 如何在 .txt 文件中存储字符串,同时不清除该文件中已有的内容 java

java - 如何在 Android 上 pretty-print JSON 原始数据

java - 在java小程序中创建xml文档

java - 如何正确关闭可变数量的流?

java - 玩! Java 8 的框架支持 可选

java - 将字符串转换为标题大小写

java - 将字节数组转换为 List<?使用 java8 扩展 Document> (org.bson.Document)

java - 另一种违反契约(Contract)的比较方法