Reputation: 18568
I receive some result sets from a database and store each row as an object of type DbRow
, this is the class:
public class DbRow {
private int clientNumber;
private String recordNumber;
private String takeoverMonth;
private int takeovers;
private int mainClaims;
private int distinctContractDates;
private LocalDate contractDate;
public DbRow(int clientNumber, String recordNumber, String takeoverMonth, int takeovers,
int mainClaims, int distinctContractDates, LocalDate contractDate) {
super();
this.clientNumber = clientNumber;
this.recordNumber = recordNumber;
this.takeoverMonth = takeoverMonth;
this.takeovers = takeovers;
this.mainClaims = mainClaims;
this.distinctContractDates = distinctContractDates;
this.contractDate = contractDate;
}
// getters & setters
// hashCode, equals & toString
}
I currently store the received objects in a Map<Integer, List<DbRow>>
in order to have them separated by a certain property (in this case clientNumber
, all the DbRow
s that have a certain client number are stored in a List<DbRow>>
while their key is this certain client number).
I need to create a Map<Integer, Map<String, Map<LocalDate, Integer>>>
out of it, which I currently do using a lot of lines of code.
The desired result can be described as
the count of distinct contract dates per takeover month per client number
(like Map<
client number, Map<
takeover month, Map<
contract date,
count>>>
)
where the takeover month is a String
of the format "yyyy/MM"
.
My current solution is ugly, but working. It contains the creation and filling of the submaps as well as checking for existing keys which I want to get rid of. Please have a look at it:
Map<Integer, List<DbRow>> records = new TreeMap<>();
// fill records with database results ...
Map<Integer, Map<String, Map<LocalDate, Integer>>> results = new TreeMap<>();
records.forEach((clientNumber, dbRows) -> {
Map<String, List<DbRow>> rowsPerMonth = dbRows.stream()
.collect(Collectors.groupingBy(DbRow::getTakeoverMonth));
Map<String, Map<LocalDate, Integer>> monthResults = new TreeMap<>();
rowsPerMonth.forEach((takeoverMonth, rows) -> {
if (monthResults.containsKey(takeoverMonth)) {
Map<LocalDate, Integer> contractDateCount = monthResults.get(takeoverMonth);
rows.forEach(dbRow -> {
LocalDate contractDate = dbRow.getContractDate();
if (contractDateCount.containsKey(contractDate)) {
int count = contractDateCount.get(contractDate);
count++;
contractDateCount.put(contractDate, count);
} else {
contractDateCount.put(contractDate, 1);
}
});
monthResults.put(takeoverMonth, contractDateCount);
} else {
Map<LocalDate, Integer> contractDateCount = new TreeMap<>();
rows.forEach(dbRow -> {
LocalDate contractDate = dbRow.getContractDate();
if (contractDateCount.containsKey(contractDate)) {
int count = contractDateCount.get(contractDate);
count++;
contractDateCount.put(contractDate, count);
} else {
contractDateCount.put(contractDate, 1);
}
});
monthResults.put(takeoverMonth, contractDateCount);
}
});
results.put(clientNumber, monthResults);
});
Does anyone know (if there is) a way to do it in a shorter way using the stream API? I really want to have a pretty solution for it.
Upvotes: 1
Views: 187
Reputation: 31868
You're possible looking for something like :
Map<Integer, Map<String, Map<LocalDate, Long>>> countDistinctDatesPerMonthPerClient(List<DbRow> input) {
return input.stream()
.collect(Collectors.groupingBy(DbRow::getClientNumber,
Collectors.groupingBy(DbRow::getTakeoverMonth,
Collectors.groupingBy(DbRow::getContractDate, Collectors.counting()))));
}
Upvotes: 2