Do we have any aggregator function in Java to perform the below aggregation?
Person {
String name;
String subject;
String department;
Long mark1;
Long mark2;
Long mark3;
}
List contains data as below.
Name |Subject |Department |Mark1 |Mark2 |Mark3 --------|-----------|-----------|-------|-------|----- Clark |English |DEP1 |7 |8 |6 Michel |English |DEP1 |6 |4 |7 Dave |Maths |DEP2 |3 |5 |6 Mario |Maths |DEP1 |9 |7 |8
The aggregation criteria is Subject & Dep. The resultant object needs to be
Subject |Department |Mark1 |Mark2 |Mark3 ----------- |-----------|-------|-------|----- English |DEP1 |13 |12 |13 Maths |DEP2 |3 |5 |6 Maths |DEP1 |9 |7 |8
This aggregation can be achieved by manually iterating through the list and create an aggregated list. Example as below.
private static List<Person> getGrouped(List<Person> origList) {
Map<String, Person> grpMap = new HashMap<String, Person>();
for (Person person : origList) {
String key = person.getDepartment() + person.getSubject();
if (grpMap.containsKey(key)) {
Person grpdPerson = grpMap.get(key);
grpdPerson.setMark1(grpdPerson.getMark1() + person.getMark1());
grpdPerson.setMark2(grpdPerson.getMark2() + person.getMark2());
grpdPerson.setMark3(grpdPerson.getMark3() + person.getMark3());
} else {
grpMap.put(key, person);
}
}
return new ArrayList<Person>(grpMap.values());
}
But is there any aggregation function or feature of Java 8 which we can leverage?
You can use reduction. Sample to aggregate mark1 is as follows.
public class Test {
static class Person {
Person(String name, String subject, String department, Long mark1, Long mark2, Long mark3) {
this.name = name;
this.subject = subject;
this.department = department;
this.mark1 = mark1;
this.mark2 = mark2;
this.mark3= mark3;
}
String name;
String subject;
String department;
Long mark1;
Long mark2;
Long mark3;
String group() {
return subject+department;
}
Long getMark1() {
return mark1;
}
}
public static void main(String[] args)
{
List<Person> list = new ArrayList<Test.Person>();
list.add(new Test.Person("Clark","English","DEP1",7l,8l,6l));
list.add(new Test.Person("Michel","English","DEP1",6l,4l,7l));
list.add(new Test.Person("Dave","Maths","DEP2",3l,5l,6l));
list.add(new Test.Person("Mario","Maths","DEP1",9l,7l,8l));
Map<String, Long> groups = list.stream().collect(Collectors.groupingBy(Person::group, Collectors.reducing(
0l, Person::getMark1, Long::sum)));
//Or alternatively as suggested by Holger
Map<String, Long> groupsNew = list.stream().collect(Collectors.groupingBy(Person::group, Collectors.summingLong(Person::getMark1)));
System.out.println(groups);
}
}
Still looking into generating the output via a single functions. Will update once completed.