I have a collection like below currently stored as a TreeMap
for sorting. Note that each month has multiple entries. How can I use Java 8 streams to filter this by the max value in each month?
date=value
2010-01-01=2100.00,
2010-01-02=2108.74,
2010-02-01=2208.74,
2010-02-02=2217.92,
2010-03-01=2317.92,
2010-03-02=2327.57,
2010-04-01=2427.57,
2010-04-02=2437.67,
2010-05-01=2537.67,
2010-05-02=2548.22,
2010-06-01=2648.22,
2010-06-02=2659.24,
2010-07-01=2759.24,
2010-07-02=2770.72,
2010-08-01=2870.72,
2010-08-02=2882.66,
2010-09-01=2982.66,
2010-09-02=2995.07,
2010-10-01=3095.07,
2010-10-02=3107.94,
2010-11-01=3207.94,
2010-11-02=3221.29
A possible solution is the following:
TreeMap
.Assuming the initial Map is of type TreeMap<LocalDate, Double>
, this would be an implementation (this code uses static imports from the Collectors
class):
TreeMap<LocalDate, Double> filtered =
map.entrySet()
.stream()
.collect(groupingBy(
e -> YearMonth.from(e.getKey()),
collectingAndThen(maxBy(Map.Entry.comparingByKey()), Optional::get))
)
.values()
.stream()
.collect(toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(v1, v2) -> { throw new IllegalStateException(); },
TreeMap::new)
);
In this code, the map is first grouped by the year-month using Collectors.groupingBy(classifier, downstream)
. The classifier returns a YearMonth
object from the LocalDate
. The downstream
collector is used to collect all the values having the same year-month into a single value: in this case, we therefore use Collectors.maxBy(comparator)
to select the maximum value according to the comparator comparing each entry LocalDate
key (comparingByKey
). Since this collector returns an Optional
(in case the Stream is empty), we wrap it into a Collectors.collectingAndThen(downstream, finisher)
where the finisher just returns the optional value. At the end of this step, we therefore have a Map<YearMonth, Map.Entry<LocalDate, Double>>
.
Finally, we keep the values
of this intermediate map to collect each entry into a new Map, where we explicitly create a TreeMap
. Since we know there are no duplicates here, the merging function simply throws a IllegalStateException
.
Sample input / output :
2010-01-01=2100.00
2010-01-02=2108.74
2010-02-01=2208.74
2010-02-02=2217.92
2010-03-01=2317.92
2010-03-02=2327.57
2010-04-01=2427.57
->
2010-01-02=2108.74
2010-02-02=2217.92
2010-03-02=2327.57
2010-04-01=2427.57
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With