代码之家  ›  专栏  ›  技术社区  ›  Deb

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

  •  7
  • Deb  · 技术社区  · 6 年前

    我有一张清单 Records . 它有两个字段: LocalDateTime instant 和A Double data .

    我要按小时对所有记录进行分组并创建一个 Map<Integer, Double> .其中键(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 回复  |  直到 6 年前
        1
  •  4
  •   Naman    6 年前

    你主要是在找 Collectors.mapping groupingBy .

    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.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)))));
    
        2
  •  2
  •   ernest_k Petronella    6 年前

    你可以使用 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 将每小时的条目作为列表,按 instant 然后字段找出两个极端元素之间的差异。

        3
  •  1
  •   Pankaj Singhal    6 年前

    基于列表将按时间戳排序的注释,以下内容将起作用 :

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