似乎与之前回答的问题类似:Java 8 stream group by min and max
然而事实并非如此!
我有一个包含三列的表格:
LogId, StartTime, EndTime
现在我们有多个具有不同StartTime和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)
答案 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
方法。