基于流java 8中的group by的最大值或最小值
与前面回答的问题类似: 但事实并非如此 我有一个有三列的表:基于流java 8中的group by的最大值或最小值,java,java-8,java-stream,Java,Java 8,Java Stream,与前面回答的问题类似: 但事实并非如此 我有一个有三列的表: LogId、开始时间、结束时间 现在我们有多个相同LogId的条目,它们的开始时间和结束时间不同 问题是: 我所有的列都是字符串,所以如何根据它们的值计算任何列的最小值或最大值 我需要通过登录到单个流中来找出min(StartTime)、max(EndTime)组 如何在Java8中使用流以最少的代码和最大的效率实现这一点 随附的是示例类: public class Log { private static final
LogId、开始时间、结束时间
现在我们有多个相同LogId的条目,它们的开始时间和结束时间不同
问题是:
如何在Java8中使用流以最少的代码和最大的效率实现这一点 随附的是示例类:
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();
}
}
公共类日志{
私有静态最终字符串inputFileName=“D:\\path\\to\\Log.csv”;
私有静态最终字符串outputFileName=“D:\\path\\to\\Output\\Log.csv”;
私有静态列表logList=null;
私有静态映射groupByLogId=newhashmap();
私有字符串日志Id;
私有字符串开始时间;
私有字符串结束时间;
公共静态映射createLogMap()引发IOException{
函数mapToLog=(行)->{
字符串[]p=line.split(“,(?=(?:[^\“]*\”[^\“]*\”[^\“]*\”*[^\“]*$)”,-1);
Log Log=新日志(p[0],p[1],
p[2]);
返回日志;
};
InputStream=null;
BufferedReader br=null;
is=新文件InputStream(新文件(inputFileName));
br=新的BufferedReader(新的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(条目entryForLog:groupByLogId.entrySet()){
System.out.println(“实体Id”+entryForLog.getKey()
+|值:“+entryForLog.getValue());
}
br.close();
返回groupByLogId;
}
公共字符串getLog_Id(){
返回日志Id;
}
公共无效设置日志Id(字符串日志Id){
this.log\u Id=log\u Id;
}
公共字符串getStartTime(){
返回起始时间;
}
公共无效设置开始时间(字符串开始时间){
this.startTime=startTime;
}
公共字符串getEndTime(){
返回结束时间;
}
公共void setEndTime(字符串endTime){
this.endTime=endTime;
}
公共静态列表getLoglist(){
返回日志列表;
}
公共日志(字符串日志Id、字符串开始时间、字符串结束时间){
超级();
this.log\u Id=log\u Id;
this.startTime=startTime;
this.endTime=endTime;
}
@凌驾
公共字符串toString(){
返回(新的StringBuffer()
.append(log_Id).append(“,”)
.append(开始时间)。append(“,”)
.append(结束时间)
).toString();
}
}
非常感谢您的帮助
预期产出:
LogId:LogId,min(StartTime),max(EndTime)
当然,将时间存储为字符串不是一个好主意。最好使用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);
}
}
这样,当出现两个具有相同
log\u Id
的日志条目时,将为它们调用merge
方法来创建合并的日志条目。“如何使用java 8中的stream以最小的代码和最大的效率实现这一点?”。“-我觉得它太宽泛了,请尝试更具体地回答您的问题。在组之前,尝试使用map
到int/long
,该代码看起来很古老。您应该使用StringBuilder
而不是StringBuffer
,但实际上,简单地使用log\u Id+“,+startTime+”,“+endTime
会自动为您带来好处。与简单表达式相比,更复杂的toString()
实现没有任何好处。此外,您应该使用try(…){…}
语句来管理资源。无需手动调用close()
,您在异常情况下无法正确关闭的问题就消失了。此外,您不再需要重复类型参数:groupByLogId=newhashmap()
将从变量推断类型。
streamOfLogs.collect(
Collectors.toMap(Log::getLog_Id, Function.identity(), Log::merge));