Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8 Stream groupingBy with custom logic

I have a list of Records. Which has two fields: LocalDateTime instant and a Double data.

I want to groupBy all the records by Hour and create a Map<Integer, Double>. Where the keys (Integer) are hours and values(Double) are last Data of that hour - first Data of that hour.

What I have done so far is following:

Function<Record, Integer> keyFunc = rec->rec.getInstant().getHour();
Map<Integer, List<Record>> valueMap = records.stream().collect(Collectors.groupingBy(keyFunc));

I want the value map to hold Double instead of List<Records>.

For Example: List records can be following:

Instant            Data
01:01:24           23.7
01:02:34           24.2
01:05:23           30.2
...
01:59:27           50.2
02:03:23           54.4
02:04:23           56.3
...
02:58:23           70.3
...

etc

Resulting map should be:

Key       Value
1          26.5 (50.2-23.7)
2          15.9 (70.3-54.4)
...
like image 449
Deb Avatar asked Feb 03 '23 20:02

Deb


1 Answers

You are mostly looking for Collectors.mapping within the groupingBy.

Map<Integer, List<Double>> valueMap = records.stream()
        .collect(Collectors.groupingBy(keyFunc, 
                Collectors.mapping(Record::getData, Collectors.toList())));

This would group Records by their instant's hour and corresponding data for such records into a List as values of the map. Based on comments further

I want to subtract the first data from the last data

Yes the list will be sorted list based on instant

you can use the grouped map to get the desired output as:

Map<Integer, Double> output = new HashMap<>();
valueMap.forEach((k, v) -> output.put(k, v.get(v.size() - 1) - v.get(0)));

Alternatively, you could use Collectors.mapping with Collectors.collectingAndThen further as:

Map<Integer, Double> valueMap = records.stream()
        .collect(Collectors.groupingBy(keyFunc,
                Collectors.mapping(Record::getData, 
                        Collectors.collectingAndThen(
                                Collectors.toList(), recs -> recs.get(recs.size() - 1) - recs.get(0)))));
like image 163
Naman Avatar answered Feb 06 '23 10:02

Naman