简体   繁体   English

Java Stream GroupBy 和 SummingInt

[英]Java Stream GroupBy and SummingInt

I have a list of class foo我有一个 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?我想根据它们的位置对 foo 列表进行分组并求和,如何使用 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 .如果我正确理解了您的要求,您希望找到属性值的total ,即每个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: 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.我假设您有一个 object 的列表,该列表具有通用名称和可变总价,并且您希望添加与该命令名称相对应的总计并显示 output 和相同的结构。 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:我假设您想要 map 案例列表到 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: 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: output:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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