对Java 8进行分组。根据给定开始时间的时间间隔进行内部分组

时间:2020-07-16 03:11:40

标签: java java-8 java-stream

我的列表格式如下:

int intervalInMinutes = 10;
String startTimeForGrouping = "2017-05-09T15:37:51.896+00:00";
List<MyObject> myObjList = Arrays.asList( 
    new MyObject("1","a","2017-05-09T15:38:51.896+00:00"),
    new MyObject("1","a","2017-05-09T16:41:51.896+00:00"),
    new MyObject("1","a","2017-05-09T16:49:51.896+00:00"),
    new MyObject("1","a","2017-05-09T16:51:51.896+00:00"),
    new MyObject("2","b","2017-05-09T17:38:51.896+00:00"),
    new MyObject("2","b","2017-05-09T18:41:51.896+00:00")
);

我以上述格式获得了清单: 我想遍历整个过程,并按照给定的开始时间间隔进行一些分组,并实现如下: 在上面的列表中,组ID 1应该返回2个列表。

单个列表中的前2个对象,因为它位于从startTimeForGrouping开始的第一个间隔中(“ 2017-05-09T15:37:51.896 + 00:00” + intervalInMinutes(10))。

第3个和第4个列表在不同的列表中,因为它位于下一个间隔中(“ 2017-05-09T15:47:51.896 + 00:00” + intervalInMinutes(10))。 ID 2也应重复同样的逻辑

我已经尝试过了

Map<String, Map<Long, List<MyObject>>> aggrResult =
myObjList.stream()
    .collect(
        Collectors.groupingBy(
            MyObject::getId,
            Collectors.groupingBy(eachQueueObj -> eachQueueObj.getIntervalStartTime()/interval)));

但这是错误的,因为我想基于给定开始时间的间隔进行汇总。

由于Java流媒体是新手,请帮助我

2 个答案:

答案 0 :(得分:3)

您应将日期字符串解析为Instant对象,然后调用Duration.between以获取持续时间。然后,将持续时间除以intervalInMinutes分钟。最后,将此数字乘以intervalInMinutes并将其添加到startTimeForGrouping中以获得分组密钥。

在流操作之前,将startTimeForGrouping解析为一个瞬间,然后从Duration中创建一个startTimeForGrouping

Instant startInstant = OffsetDateTime.parse(startTimeForGrouping).toInstant();
Duration interval = Duration.ofMinutes(startTimeForGrouping);

然后您可以声明方法roundInstant

public static Instant roundInstant(Instant instant, Duration interval, Instant start) {
    long multiple =
            Duration.between(start, instant)
                .getSeconds() / interval.getSeconds();
    return start.plus(interval.multipliedBy(multiple));
}

第二个groupingBy调用可以如下所示:

Collectors.groupingBy(
    eachQueueObj -> roundInstant(
        OffsetDateTime.parse(eachQueueObj.getIntervalStartTime()).toInstant(),
        interval,
        startInstant
    ).getEpochSecond()
)

事实上,我建议您不要使用StringLong,而直接使用Instant

答案 1 :(得分:1)

我认为代码是,您可以尝试重新修改getTime方法以解决您的需求

 package com.test;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 *
 *
 *
 *
 *
 *
 * @author shikai.liu
 * @version 1.0
 * @since JDK1.7
 */
public class TestList {

    public static String strDateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX";
    public static SimpleDateFormat sdf = new SimpleDateFormat(strDateFormat);

    public static class MyObject {
        public String id;
        public String code;
        public String time;

        public MyObject(String id, String code, String time) {
            this.code = code;
            this.id = id;
            this.time = time;
        }

        public String getId() {
            return this.id;
        }

        public String getIntervalStartTime() {
            return time;
        }

        public long getTime(Integer t, String srcTime) {
            long result = 0;
            try {

                Date dstDate = sdf.parse(time);
                Date srcDate = sdf.parse(srcTime);
                long inteval = dstDate.getTime() - srcDate.getTime();

                result = inteval / (1000 * 60) / t;
            } catch (Exception e) {
                e.printStackTrace();
            }

            return result;
        }
    }

    public static void main(String[] args) throws Exception {
        int intervalInMinutes = 10;
        String startTimeForGrouping = "2017-05-09T15:37:51.896+00:00";
        List<MyObject> myObjList = Arrays.asList(new MyObject("1", "a", "2017-05-09T15:38:51.896+00:00"), new MyObject("1", "a",
                "2017-05-09T16:41:51.896+00:00"), new MyObject("1", "a", "2017-05-09T16:49:51.896+00:00"), new MyObject("1", "a",
                "2017-05-09T16:51:51.896+00:00"), new MyObject("2", "b", "2017-05-09T17:38:51.896+00:00"), new MyObject("2", "b",
                "2017-05-09T18:41:51.896+00:00"));

        Map<String, Map<Long, List<MyObject>>> aggrResult = myObjList.stream().collect(
                Collectors.groupingBy(MyObject::getId, Collectors.groupingBy(a -> a.getTime(intervalInMinutes, startTimeForGrouping))));
        System.out.println(1);
    }
}