(Sorry if the term "bracket" is confusing, I took it from "tax brackets" as translated from dutch).
How can I collect items into groups and each preceding group based on a property threshold?
Example:
Loan A, duration of 6 months
Loan B, duration of 10 months
Loan C, duration of 12 months
Result as Map<Integer, List<Loan>>
:
6 -> {A, B, C}
10 -> {B, C}
12 -> {C}
Currently I'm going the LinkedHashMap route and then after collecting the items from stream, run through all groups to update them:
Map<Integer, List<Loan>> loansByDuration = loans.stream()
.collect(groupingBy(Loan::getDuration, LinkedHashMap::new, toList()));
List<Loan> previousGroup = null;
for (List<Loan> currentGroup : loansByDuration.values()) {
if (previousGroup != null) {
currentGroup.addAll(previousGroup);
}
previousGroup = currentGroup;
}
So what I'm doing is every subsequent list-value in the map will have all previous loans plus the loans only relevant for respective duration-key. Similar to cumulative subtotals.
Can this be done with standard API or else something like a custom collector?
For the use case is it necessary to work with a type like Map<Integer, List<Loan>>
? Thus every list will have all previous loans. This means there would be redundant references to Loan
.
Or is the use case to provide views on loans
grouped by duration
?
In such a case we can use an alternative approach: A view on the loans using Stream
(based on Java 9+).
public class Loans {
private final List<Loan> loans;
public Loans(List<Loan> loans) {
this.loans = loans.stream()
.sorted(Comparator.comparingInt(Loan::getDuration))
.collect(Collectors.toList());
}
public Stream<Loan> getUpTo(int duration) {
return loans.stream().takeWhile(l -> l.getDuration() <= duration);
}
}
Since we have a List<Loan>
sorted by duration
we can use Stream.takeWhile
to get a Stream
of the desired Loan
s for a certain duration
.
This works e.g. like that:
Loans loans = new Loans(List.of(new Loan("A", 6), new Loan("B", 10), new Loan("C", 12));
loans.getUpTo(1); // <empty>
loans.getUpTo(5); // <empty>
loans.getUpTo(6); // Loan("A", 6)
loans.getUpTo(10); // Loan("A", 6), new Loan("B", 10)
loans.getUpTo(11); // Loan("A", 6), new Loan("B", 10)
loans.getUpTo(12); // Loan("A", 6), new Loan("B", 10), Loan("C", 12)
loans.getUpTo(100); // Loan("A", 6), new Loan("B", 10), Loan("C", 12)
In case a List<Loan>
should be needed, we can still collect
the streamed elements toList()
.