基于流java 8中的group by的最大值或最小值

时间:2016-12-22 02:13:26

标签: java java-8 java-stream

似乎与之前回答的问题类似:Java 8 stream group by min and max

然而事实并非如此!

我有一个包含三列的表格: LogId, StartTime, EndTime

现在我们有多个具有不同StartTime和EndTime的LogId的条目

问题是:

  1. 我拥有的所有列都是String,因此如何根据值来计算任何列的最小值或最大值。

  2. 我需要通过LogId将min(StartTime),max(EndTime)组找到一个Stream。

  3. 如何使用java 8中的流以最少的代码和最大的效率实现这一目标。

    附件是Sample类:

    public class Log {  
    
        private static final String inputFileName = "D:\\path\\to\\Log.csv";
    
        private static final String outputFileName = "D:\\path\\to\\Output\\Log.csv";
    
        private static List<Log> logList = null;
    
        private static Map<String, List<Log>> groupByLogId = new HashMap<String, List<Log>>();
    
        private String log_Id;
        private String startTime;
        private String endTime;
    
        public static Map<String, List<Log>> createLogMap() throws IOException {
            Function<String, Log> mapToLog = (line) -> {
                String[] p = line.split(",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)", -1);
                Log log = new Log(p[0],p[1],
                        p[2]);
    
                return log;
            };
    
    
            InputStream is = null;
            BufferedReader br = null;
    
                is = new FileInputStream(new File(inputFileName));
    
                br = new BufferedReader(new InputStreamReader(is));
    
                logList = br.lines()
                                .skip(1)
                                .map(mapToLog)
                                .collect(Collectors.toList());
    
    
    
    
                logList.stream().forEach(System.out::println);
    
                groupByLogId = logList.stream()
                                .collect(Collectors.groupingBy(Log::getLog_Id));
    
    
                for (Entry<String, List<Log>> entryForLog : groupByLogId.entrySet()) {
                    System.out.println(" Entity Id " + entryForLog.getKey()
                            + "        |        Value : " + entryForLog.getValue());
                }
    
    
    
    
    
    
                br.close();
                return groupByLogId;
    
    
    
        }
    
    
    
        public String getLog_Id() {
            return log_Id;
        }
    
    
    
        public void setLog_Id(String log_Id) {
            this.log_Id = log_Id;
        }
    
    
    
        public String getStartTime() {
            return startTime;
        }
    
    
    
        public void setStartTime(String startTime) {
            this.startTime = startTime;
        }
    
    
    
        public String getEndTime() {
            return endTime;
        }
    
    
    
        public void setEndTime(String endTime) {
            this.endTime = endTime;
        }
    
    
    
        public static List<Log> getLoglist() {
            return logList;
        }
    
    
    
        public Log(String log_Id, String startTime, String endTime) {
            super();
            this.log_Id = log_Id;
            this.startTime = startTime;
            this.endTime = endTime;
        }
    
    
    
        @Override
        public String toString() {
    
            return (new StringBuffer()
                        .append(log_Id).append(",")
                        .append(startTime).append(",")
                        .append(endTime)
                        ).toString();
    
        }
    
    
    }
    

    非常感谢任何帮助,

    预期产出:

    LogId: logid,min(StartTime),max(EndTime)

1 个答案:

答案 0 :(得分:1)

当然,将时间存储为字符串并不是一个好主意。最好使用LocalDateTime之类的东西。在这个答案中,我假设您的字符串时间戳表示具有可比性,因此我可以使用date1.compareTo(date2)

此外,我强烈建议您删除使Log个对象不可变的setter。它们不会添加任何值,只会在您偶尔更改现有对象时使程序更难调试。

回到你的问题,添加如下的合并方法:

class Log {
    ...
    Log merge(Log other) {
        if(!other.getLog_Id().equals(this.getLog_Id())) {
            throw new IllegalStateException();
        }
        String start = this.getStartTime().compareTo(other.getStartTime()) < 0 ?
                       this.getStartTime() : other.getStartTime();
        String end = this.getEndTime().compareTo(other.getEndTime()) > 0 ?
                     this.getEndTime() : other.getEndTime();
        return new Log(this.getLog_Id, start, end);
    }
}

现在您只需使用toMap()收集器来提供合并功能:

streamOfLogs.collect(
    Collectors.toMap(Log::getLog_Id, Function.identity(), Log::merge));

这样,当出现两个具有相同Log_Id的日志条目时,将为它们创建合并的日志条目调用merge方法。