简体   繁体   中英

Java Stream GroupBy and SummingInt

I have a list of class foo

class foo(){
  private String location;
  private int total;

  //constructor, getters, and setters
}

I want to group the list of foo according to their location and sum the total, how can I achieve it with Java Streams?

expected output
[
  {
    "location" = "locationA",
    "total" = 123
  },
  {
    "location" = "locationB",
    "total" = 167
  }
]

What I have achieved:

{locationA=123, locationB=167}

My code:

static Function<List<Case>, Object> totalPerYear = cases -> cases.stream()
                                                   .collect(Collectors.groupingBy((Case c)->c.getYear(), 
                                                   Collectors.summingInt((Case c)->c.getNumber())));

If I understood your requirement correctly, you want to find the sum of the value of the attribute, total for each location . If yes, you can do it as follows:

Map<String, Integer> map = 
    list.stream()
    .collect(Collectors.groupingBy(Foo::getLocation, Collectors.summingInt(Foo::getTotal)));

Demo:

public class Main {
    public static void main(String[] args) {
        List<Foo> list = List.of(new Foo("x", 10), new Foo("y", 5), new Foo("x", 15), new Foo("y", 10),
                new Foo("z", 10), new Foo("a", 10));

        Map<String, Integer> map = 
                list.stream()
                .collect(Collectors.groupingBy(Foo::getLocation, Collectors.summingInt(Foo::getTotal)));

        System.out.println(map);
    }
}

Output:

{a=10, x=25, y=15, z=10}

I assume you have a list of an object with a common name and variable total price and you wish to add total corresponding to that command name and present the output and the same structure. Here is how I tried to do it:

package com.example;

import com.google.gson.Gson;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

class LocationData {
    String name;
    int total;

    public LocationData(String name, int total) {
        this.name = name;
        this.total = total;
    }

    public enum LocationNames {
        LocationA,
        LocationB,
        LocationC,
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getTotal() {
        return total;
    }

    public void setTotal(int total) {
        this.total = total;
    }
}

public class SampleStreamGroupBy {
    public static void main(String[] args) {
        List<LocationData> input = new ArrayList<>();
        input.add(new LocationData(LocationData.LocationNames.LocationA.name(), 1));
        input.add(new LocationData(LocationData.LocationNames.LocationA.name(), 2));
        input.add(new LocationData(LocationData.LocationNames.LocationA.name(), 3));
        input.add(new LocationData(LocationData.LocationNames.LocationB.name(), 4));
        input.add(new LocationData(LocationData.LocationNames.LocationB.name(), 100));
        input.add(new LocationData(LocationData.LocationNames.LocationC.name(), 5));

        Map<String, Integer> collect = input.stream()
                .collect(Collectors.groupingBy(LocationData::getName, Collectors.summingInt(LocationData::getTotal)));
        System.out.println(collect);

        List<LocationData> locationDataList = collect.entrySet().stream()
                .map(entry -> new LocationData(entry.getKey(), entry.getValue()))
                .collect(Collectors.toList());
        System.out.println(new Gson().toJson(locationDataList));
    }
}

Should print something similar to this

{LocationC=5, LocationA=6, LocationB=104}
[{"name":"LocationC","total":5},{"name":"LocationA","total":6},{"name":"LocationB","total":104}]

I assumed you want to map list of cases to list of foos:

class Main {

    private static List<Integer> costsList;

    public static void main(String args[]) throws Exception {
        List<Case> list = new ArrayList<>();
        list.add(new Case("2020", 4));
        list.add(new Case("2021", 2));
        list.add(new Case("2020", 2));
        list.add(new Case("2022", 3));
        List<Foo> foos = totalPerYear.apply(list);
        foos.forEach(System.out::println);

    }


    static Function<List<Case>, List<Foo>> totalPerYear = cases -> cases.stream()
            .collect(Collectors.groupingBy(Case::getYear, Collectors.summingInt(Case::getNumber)))
            .entrySet()
            .stream()
            .map(entry -> new Foo(entry.getKey(), entry.getValue()))
            .collect(Collectors.toList());


    static class Foo {
        private String year;
        private int total;

        public Foo(String year, int total) {
            this.year = year;
            this.total = total;
        }

        public String getYear() {
            return year;
        }

        public void setYear(String year) {
            this.year = year;
        }

        public int getTotal() {
            return total;
        }

        public void setTotal(int total) {
            this.total = total;
        }

        @Override
        public String toString() {
            return "Foo{" +
                    "year='" + year + '\'' +
                    ", total=" + total +
                    '}';
        }
    }

    static class Case {
        private String year;
        private int number;

        public Case(String year, int number) {
            this.year = year;
            this.number = number;
        }

        public String getYear() {
            return year;
        }

        public void setYear(String year) {
            this.year = year;
        }

        public int getNumber() {
            return number;
        }

        public void setNumber(int number) {
            this.number = number;
        }
    }
}

Output:

Foo{year='2022', total=3} 
Foo{year='2021', total=2} 
Foo{year='2020', total=6}
    var data = List.of(
        new Foo("A", 17),
        new Foo("B", 30),
        new Foo("Y", 68),
        new Foo("A", 30),
        new Foo("B", 25),
        new Foo("Y", 51),
        new Foo("Z", 1)
    );

    var result = data.stream()
        .collect(Collectors.groupingBy(Foo::getLocation, Collectors.summingInt(Foo::getTotal)));

output:

result = {A=47, B=55, Y=119, Z=1} 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM