【问题标题】:Find average using java 8 streams使用 java 8 流求平均值
【发布时间】:2019-02-27 04:14:30
【问题描述】:

我是 java 8 的新手,仍处于学习阶段。我必须使用 java 8 编写以下逻辑。我有一个 Json Array 数据,我的 json 结构如下。

{"list":[{"core":{"min":281.556,"max":286.67,"top":972.73},"dt":"2017-02-16 12:00:00"},{"core":{"min":281.821,"max":285.66,"top":970.91},"dt":"2017-02-16 15:00:00"},{"core":{"min":274.498,"max":277.05,"top":970.44},"dt":"2017-02-16 18:00:00"},{"core":{"min":271.503,"max":272.78,"top":969.32},"dt":"2017-02-16 21:00:00"}]}

这个 jsonArray 将包含大约 100 个 jsonObject,其中包含每 3 小时的数据。我实际上需要使用 java 8 流或使用其他 java 8 功能分别找到 min 和 max 的平均值和 top 的平均值。另一个标准是最小值和最大值平均值应基于白天或晚上。如果 dt 包含 06:00 或 09:00 或 12:00 或 15:00,则它应该是 dayavg(白天的最小值 + 最大值),否则它应该是夜间平均值((夜间的最小值 + 最大值))。顶部不取决于白天或黑夜。任何帮助表示赞赏

以下是使用 java 7 登录。需要使用 Java 8 功能。

int dayavg=0;
        int nightavg = 0;
        int topavg=0;
        int day=0;
        int night = 0;
        int top=0;
    for(int i=0;i<50;i++){
        JsonNode node = list.get(i);
        String dt = node.get("dt").textValue();
        if(dt.contains("06:00:00")|| dt.contains("09:00:00") || dt.contains("12:00:00") || dt.contains("15:00:00")){
            int val = node.get("core").get("min").asInt() + node.get("core").get("max").asInt();
            day = day + val;
        }
        if(dt.contains("18:00:00")|| dt.contains("21:00:00") || dt.contains("00:00:00") || dt.contains("03:00:00")){
            int val = node.get("core").get("min").asInt() + node.get("core").get("max").asInt();
            night = night + val;
        }
        int val = node.get("core").get("top").asInt();
        top = top + val;
    }
    topavg = top/50;
    dayavg = day/100;
    nightavg = night/100;

【问题讨论】:

  • IntStream.range(0, 50).forEach(index -> list.get(index).get("dt_txt").textValue().concat("06:00:00") );我正在尝试类似的东西。使用通常的循环,我可以轻松地做到这一点。只需从 json 读取数据并对其进行平均。但需要使用 Java 8 特性来实现
  • 用所需的逻辑更新了问题

标签: java java-8 java-stream jackson-databind


【解决方案1】:

您可以使用自定义enum

static enum Type { DAY, NIGHT, TOP }

然后收集两次你的清单:

// Day and night
Map<Type, Double> result = list.stream()
.collect(
    Collectors.groupingBy(node -> {
        String dt = node.get("dt").textValue();
        if(dt.contains("06:00:00")|| dt.contains("09:00:00") || dt.contains("12:00:00") || dt.contains("15:00:00")){
            return Type.DAY;
        }
        if(dt.contains("18:00:00")|| dt.contains("21:00:00") || dt.contains("00:00:00") || dt.contains("03:00:00")){
            return Type.NIGHT;
        }
        // Should not happen
        return null;
    },
    Collectors.averagingInt(node -> node.get("core").get("min").asInt() + node.get("core").get("max").asInt()))
);

// Top
result.putAll(
     list.stream().collect(
         Collectors.groupingBy(node -> Type.TOP,
         Collectors.averagingInt(node -> node.get("core").get("top").asInt()))
     )
);

【讨论】:

  • 我认为这是一个非常好的解决方案,我认为我宁愿为 Top value 做类似的事情:result.put(Type.TOP,list.stream().collect( Collectors.averagingInt(node -&gt; node.get("core").get("top").asInt()) )); 因为 Group By 并不是真的有用
  • 是的,我同意,为了演示,我想保留两次相同的逻辑
  • 感谢您的解决方案!
【解决方案2】:

制作你自己的收藏家

如果你只想拥有一个流,你可以做你自己的收集器

有两个这样的 POJO:

class Values {
    int top,day,night;
}

class Avg {
    int topAvg,dayAvg,nightAvg;
}

收集器将如下所示:

    BinaryOperator<Values> combiner = (left,right) -> {
        left.day+=right.day;
        left.night+=right.night;
        left.top+=right.top;
        return left;
    };

    Function<Values,Avg> finisher =(value)->{
        Avg avg = new Avg();
        avg.topAvg = value.top/50;
        avg.dayAvg = value.day/100;
        avg.nightAvg = value.night/100;
        return avg;
    };


    BiConsumer<Values,JsonNode> accumulator= (values, node) ->{
        String dt = node.get("dt").textValue();
        if(dt.contains("06:00:00")|| dt.contains("09:00:00") || dt.contains("12:00:00") || dt.contains("15:00:00")){
            int val = node.get("core").get("min").asInt() + node.get("core").get("max").asInt();
            values.day +=  val;
        }
        if(dt.contains("18:00:00")|| dt.contains("21:00:00") || dt.contains("00:00:00") || dt.contains("03:00:00")){
            int val = node.get("core").get("min").asInt() + node.get("core").get("max").asInt();
            values.night += val;
        }
        int val = node.get("core").get("top").asInt();
        values.top += val;
    };

    Avg avg = list.stream()
        .collect(Collector.of(Values::new, accumulator,combiner,finisher));

按值使用一个流

您也可以使用多个流并为 dayAvg 设置类似的内容:

   OptionalDouble dayAvg = list.stream()
        .filter(node -> {
            String dt = node.get("dt").textValue();
            return dt.contains("06:00:00") || dt.contains("09:00:00") || dt.contains("12:00:00") || dt.contains("15:00:00");
        })
        .mapToInt(node -> node.get("core").get("min").asInt() + node.get("core").get("max").asInt())
        .average();

我认为它更清晰,但它可能会降低方法的性能

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-03
    • 2021-03-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多