似乎类似于先前回答的问题: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
方法以创建合并的日志条目。