Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find average using java 8 streams

Tags:

Am new to java 8 and still in learning phase. I have to write the below logic using java 8. I have an Json Array data and my json structure is as below.

{"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"}]}

This jsonArray will have around 100 jsonObject in it with data for every 3 hours. I actually need to find the average of min with max separately and average of top separately using java 8 stream or using other java 8 features. Another criteria is min and max average should be based on day or night. if dt contains like 06:00 or 09:00 or 12:00 or 15:00, it should be dayavg(min+max for daytime) or else it should be night average((min+max for nighttime)). Top doesn't depend on day or night. Any help appreciated

Below is the login using java 7. need this using Java 8 features.

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;
like image 821
RK3 Avatar asked Sep 23 '18 12:09

RK3


1 Answers

Make your own collector

If you want to have only one stream you could do your own collectors

With two POJOs like this :

class Values {
    int top,day,night;
}

class Avg {
    int topAvg,dayAvg,nightAvg;
}

The collectors will look like this :

    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));

Using one stream by value

You also could use multiple stream and have something like that for the 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();

I think it's clearer but it might reduce the performance of the method

like image 60
Matthieu Gabin Avatar answered Sep 23 '22 09:09

Matthieu Gabin