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

但是事实并非如此!

我有一个带有三列的表:
LogId, StartTime, EndTime

现在,我们有多个具有相同StartId和EndTime的相同LogId的条目

问题是:


我拥有的所有列都是String,因此如何根据其值计算任何列的最小值或最大值。
我需要通过LogId找出min(StartTime),max(EndTime)组到单个Stream中。


如何使用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)

最佳答案

当然,将时间存储为字符串不是一个好主意。最好使用类似LocalDateTime的名称。在这个答案中,我假设您的字符串时间戳表示形式是可比较的,所以我可以使用date1.compareTo(date2)

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

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

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方法以创建合并的日志条目。

09-25 20:43