Reputation: 447
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())));
Upvotes: 1
Views: 1818
Reputation: 6963
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}]
Upvotes: 2
Reputation: 784
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}
Upvotes: 2
Reputation: 512
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}
Upvotes: 1
Reputation: 79015
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}
Upvotes: 2