Java 8流分组通过自定义逻辑

时间:2018-12-29 06:33:03

标签: java java-8 java-stream

我有一个Records的列表。其中有两个字段:LocalDateTime instantDouble data

我想按小时将所有记录分组,并创建一个Map<Integer, Double>。键(整数)是小时,值(双精度)是该小时的最后一个数据-该小时的第一个数据。

我到目前为止所做的是:

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

我希望值映射表保留Double而不是List<Records>

例如:列表记录可以如下:

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
...

结果图应为:

Key       Value
1          26.5 (50.2-23.7)
2          15.9 (70.3-54.4)
...

3 个答案:

答案 0 :(得分:4)

您主要是在groupingBy中寻找Collectors.mapping

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

这会将Record按其instant的小时数和此类记录的相应数据分组到List中,作为地图的值。根据评论进一步

  

我要从最后一个数据中减去第一个数据

     

是的,列表将基于即时排序

您可以使用分组地图以如下方式获得所需的输出:

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

或者,您也可以将Collectors.mappingCollectors.collectingAndThen结合使用:

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)))));

答案 1 :(得分:2)

您可以将SUM(g.branchid=30) 用作collectingAndThen的下游收集器,并使用每个组的两个极值来计算差异:

groupingBy

Map<Integer, Double> result = records.stream() .collect( Collectors.groupingBy(rec -> rec.getInstant().getHour(), Collectors.collectingAndThen( Collectors.toList(), list -> { //please handle the case of 1 entry only list.sort(Comparator.comparing(Record::getInstant)); return list.get(list.size() - 1).getData() - list.get(0).getData(); }))); 将按小时对条目进行分组。如此处使用的,Collectors.groupingBy(rec -> rec.getInstant().getHour()将按小时输入条目作为列表,并按Collectors.collectingAndThen字段对每个此类列表进行排序,然后找出两个极端元素之间的差异。

答案 2 :(得分:1)

基于注释,该列表将根据时间戳进行排序,因此可以进行以下操作 :

    Map<Integer, Double> valueMap = records.stream()
            .collect(Collectors.groupingBy(rec -> rec.getInstant().getHour(),
                    Collectors.mapping(Record::getData,
                        Collectors.collectingAndThen(Collectors.toList(),recs -> recs.get(recs.size()-1) - recs.get(0)))));