Reputation: 23
I have a class Row such as:
class Row {
public Long id1;
public String id2;
public Long metric1;
public Long metric2;
public Stats getStats() {
return new Stats(metric1, metric2);
}
}
and a class Stats:
class Stats{
public Long totalMetric1;
public Long totalMetric2;
public void addMetric1(Long metric1) {
this.totalMetric1 = this.totalMetric1 + metric1;
}
public void addMetric2(Long metric2) {
this.totalMetric2 = this.totalMetric2 + metric2;
}
}
I have a list of rows
List<Row> rowList;
and i need to convert it into a map grouped by id1 and id2, and i need the metric data to be summed up into Stats object in this form
Map<Long, Map<String, Stats>>
I am using java stream to generate this but stuck at this point:
Map<Long, Map<String, List<Stats>>> map = stream.collect(
Collectors.groupingBy(r->r.id1(),
Collectors.groupingBy(r->r.id2,
Collectors.mapping(r->r.getStats(), Collectors.toList()))));
How do i convert the list into another object having sum of all the objects in that list?
Also is there a way to merge two output maps of above required form into a third one using java stream?
Example:-
Input: A list of Rows
<1,"ABC", 1, 2>
<1,"ABC", 2, 2>
<1,"XYZ", 1, 2>
<2,"ABC", 1, 2>
<2,"XYZ", 1, 2>
<3,"XYZ", 1, 0>
<3,"XYZ", 2, 1>
<3,"XYZ", 2, 3>
Result: Map grouped by Field 1, Field 2, with sum of Field 3 and Field 4
1 - ABC - 3,4
XYZ - 1,2
2 - ABC - 1,2
XYZ - 1,2
3 - XYZ - 5,4
Upvotes: 2
Views: 2736
Reputation: 3698
My suggestion would be to do it in bit easier way than nested collections. in Row class, add
public Pair<Long,String> getIds() {
return new Pair<>(id1,id2);
}
in Stats class, add
public Stats merge(Stats other) {
return new Stats(totalMetric1+other.totalMetric1, totalMetric2 + other.totalMetric2);
}
and then write something like
Map<Pair<Long, String>, Stats> stats = rowList.stream().
collect(Collectors.toMap(Row::getIds,Row::getStats, (s1,s2) -> s1.merge(s2)));
If you are not allergic to guava (and you shouldn't be, this is one of no-brainer libraries to include in every project, at least for me), you can write it in more elegant and readable
Table<Long, String, Stats> table = rowList.stream().
collect(Tables.toTable(Row::getId1, Row::getId2, Row::getStats,(s1,s2) -> s1.merge(s2),HashBasedTable::create));
without having to use Pair<> or nested maps.
Upvotes: 1