Home > Back-end >  Java 8 - Replace each row with GroupBy sum
Java 8 - Replace each row with GroupBy sum

Time:02-03

I have class Data which have 4 fields and have list of values then i want replace each row groupby year and sum value for same year using java 8 and stream. please see below code and output.

class Data {
    int id;
    int year;
    String name;
    double value;
}

List<Data> list = new ArrayList<>();
list.add(new Data(101, 2018, "AAA", 20));
list.add(new Data(102, 2019, "BBB", 30));
list.add(new Data(103, 2020, "CCC", 10));
list.add(new Data(104, 2019, "DDD", 50));
list.add(new Data(105, 2020, "EEE", 40));
list.add(new Data(106, 2020, "FFF", 60));

First code try:

list.stream().collect(Collectors.groupingBy(Data::getYear, Collectors
    .summingDouble(Data::getValue)));

Second code try:

list.stream().collect(Collectors.toMap(value -> value.getYear(), Function.identity(),
            (a, b) -> new Data(a.getId(), a.getYear(), a.getName(), a.getValue()   b.getValue()))).values()
            .forEach(value -> System.out.println(value));

Output:

id    year   name   value
101   2018   "AAA"   20
102   2019   "BBB"   80
103   2020   "CCC"   110

Expected Output:

id    year   name   value
101   2018   "AAA"   20
102   2019   "BBB"   80
103   2020   "CCC"   110
104   2019   "DDD"   80
105   2020   "EEE"   110
106   2020   "FFF"   110 

CodePudding user response:

Map created by the second stream in your code preserves only a single entry per year.

Remaping function (a, b) -> new Data(a.getId(), a.getYear(), a.getName(), a.getValue() b.getValue())) takes care about the duplicates so that value of each data object will be the sum of all values.

In order to retain all the Data and change the value of every object to be a total value for the given year, you have to take several steps:

  • create a map: year --> total value per year (which is already done correcl);
  • create a map: year --> list of Data objects;
  • apply the total value per year to each of the Data objects.
    public static void main(String[] args) {
        List<Data> dataList = List.of(
                new Data(101, 2018, "AAA", 20),
                new Data(102, 2019, "BBB", 30),
                new Data(103, 2020, "CCC", 10),
                new Data(104, 2019, "DDD", 50),
                new Data(105, 2020, "EEE", 40),
                new Data(106, 2020, "FFF", 60)
        );

        Map<Integer, Double> yearToTotalVal = getTotalValueMap(dataList);

        Map<Integer, List<Data>> yearToData = getYearToDataListMap(dataList);

        appllyTotalValue(yearToTotalVal, yearToData);

        for (Map.Entry<Integer, List<Data>> entry: yearToData.entrySet()) {
            System.out.println(entry);
        }
    }
    private static Map<Integer, Double> getTotalValueMap(List<Data> dataList) {
        return dataList.stream()
                .collect(Collectors.groupingBy(Data::getYear,
                                    Collectors.summingDouble(Data::getValue)));
    }

    private static Map<Integer, List<Data>> getYearToDataListMap(List<Data> dataList) {
        return dataList.stream()
                .collect(Collectors.groupingBy(Data::getYear));
    }
    private static void appllyTotalValue(Map<Integer, Double> yearToTotalVal, 
                                         Map<Integer, List<Data>> yearToData) {
        for (Integer year: yearToTotalVal.keySet()) {
            yearToData.get(year)
                    .replaceAll(data -> new Data(data.getId(),
                                                data.getYear(),
                                                data.getName(),
                                                yearToTotalVal.get(year)));
        }
    }

output - data for each year:

2018=[Data{id=101, year=2018, name='AAA', value=20.0}]
2019=[Data{id=102, year=2019, name='BBB', value=80.0}, Data{id=104, year=2019, name='DDD', value=80.0}]
2020=[Data{id=103, year=2020, name='CCC', value=110.0}, Data{id=105, year=2020, name='EEE', value=110.0}, Data{id=106, year=2020, name='FFF', value=110.0}]

Side note:

  • I also advise you to make the Data class immutable
    public class Data {
        private final int id;
        private final int year;
        private final String name;
        private final double value;

        // Constractor, geters, etc
    }
  •  Tags:  
  • Related