有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

具有自定义逻辑的Java8流分组

我有一个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) 个答案

  1. # 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)))));
    
  2. # 2 楼答案

    您可以使用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. # 3 楼答案

    您主要是在groupingBy中查找^{}

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

    这将Record按其instant小时和此类记录的相应数据分组为List作为映射的值。根据进一步的评论

    I want to subtract the first data from the last data

    Yes the list will be sorted list based on instant

    您可以使用分组映射获得所需的输出,如下所示:

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

    或者,您还可以将^{}^{}一起使用,如下所示:

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