我有一个日志文件,如下所示:
LSR2019-07-12_12:07:21.554
KMH2019-07-12_12:09:44.291
RGH2019-07-12_12:29:28.352
RGH2019-07-12_12:33:08.603
我有一个解析器,它将数据解析为缩写/日期/时间:
public Map <String, ?> parse() throws IOException {
try (Stream<String>lines = Files.lines(path)){
return lines.collect(Collectors.toMap(
string -> string.substring(0,3),
string -> new DateAndTimeInfo(LocalTime.from(DateTimeFormatter.ofPattern("HH:mm:ss.SSS").parse((string.substring(3).split("_")[1]))),
LocalDate.parse(string.substring(3).split("_")[0], DateTimeFormatter.ofPattern("yyyy-MM-dd"))),
(string1, string2)-> ??? )); //Struggle here
解析后,它创建了一个映射,其中包含缩写作为DateAndTimeInfo类的键和实例。类看起来是这样的:
public class DateAndTimeInfo {
private List<LocalTime> localTime;
private List<LocalDate> localDate;
public DateAndTimeInfo(LocalTime localTime, LocalDate localDate) {
this.localTime = Arrays.asList(localTime);
this.localDate = Arrays.asList(localDate);
}
public List<LocalTime> getLocalTime() {
return this.localTime;
}
public List<LocalDate> getLocalDate() {
return this.localDate;
}
public void addAnotherLapTime(LocalTime localtime, LocalDate localDate) {
this.localTime.add(localtime);
this.localDate.add(localDate);
}
}
在日志文件有重复的缩写之前,一切都很正常。一旦出现重复键,我希望数据存储在DateAndTimeInfo对象中,该对象是在解析第一个重复键时创建的。为此,我使用了addAnotherLapTime()
方法。问题是我不知道如何把它写在我的流中。
由于值的组合最终会出现在List
对象中,因此这是groupingBy
收集器的任务。
但首先,您必须修复DateAndTimeInfo
类。这是唯一的构造函数
public DateAndTimeInfo(LocalTime localTime, LocalDate localDate) {
this.localTime = Arrays.asList(localTime);
this.localDate = Arrays.asList(localDate);
}
创建固定大小的列表,因此方法
public void addAnotherLapTime(LocalTime localtime, LocalDate localDate) {
this.localTime.add(localtime);
this.localDate.add(localDate);
}
将失败,但有例外。
当你使用
public class DateAndTimeInfo {
private List<LocalTime> localTime;
private List<LocalDate> localDate;
public DateAndTimeInfo() {
localTime = new ArrayList<>();
localDate = new ArrayList<>();
}
public List<LocalTime> getLocalTime() {
return this.localTime;
}
public List<LocalDate> getLocalDate() {
return this.localDate;
}
public void addAnotherLapTime(LocalTime localtime, LocalDate localDate) {
this.localTime.add(localtime);
this.localDate.add(localDate);
}
}
相反,你可以像一样收集地图
public Map<String, DateAndTimeInfo> parse() throws IOException {
DateTimeFormatter f = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH:mm:ss.SSS");
try(Stream<String>lines = Files.lines(path)){
return lines.collect(Collectors.groupingBy(
string -> string.substring(0,3),
Collector.of(DateAndTimeInfo::new, (info,str) -> {
LocalDateTime ldt = LocalDateTime.parse(str.substring(3), f);
info.addAnotherLapTime(ldt.toLocalTime(), ldt.toLocalDate());
}, (info1,info2) -> {
info1.getLocalDate().addAll(info2.getLocalDate());
info1.getLocalTime().addAll(info2.getLocalTime());
return info1;
})));
}
}
groupingBy
允许为组指定收集器,并且该解决方案为DateAndTimeInfo
对象创建新的自组织Collector
。
你可以考虑是否真的想把日期和时间放在不同的列表中。
另一种选择是:
public class DateAndTimeInfo {
private List<LocalDateTime> localDateTimes;
public DateAndTimeInfo(List<LocalDateTime> list) {
localDateTimes = list;
}
public List<LocalDateTime> getLocalDateTimes() {
return localDateTimes;
}
// in case this is really needed
public List<LocalTime> getLocalTime() {
return localDateTimes.stream()
.map(LocalDateTime::toLocalTime)
.collect(Collectors.toList());
}
public List<LocalDate> getLocalDate() {
return localDateTimes.stream()
.map(LocalDateTime::toLocalDate)
.collect(Collectors.toList());
}
}
然后
public Map<String, DateAndTimeInfo> parse() throws IOException {
DateTimeFormatter f = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH:mm:ss.SSS");
try(Stream<String>lines = Files.lines(path)){
return lines.collect(Collectors.groupingBy(
string -> string.substring(0,3),
Collectors.collectingAndThen(
Collectors.mapping(s -> LocalDateTime.parse(s.substring(3), f),
Collectors.toList()),
DateAndTimeInfo::new)));
}
}
你可以试试这个。我添加了lambdas,让它看起来更干净。基本上,它使用toMap的merge函数将列表从新创建的类复制到已经存在的类。这是我为你们班做的MOD。
- 构造函数将值放入列表中
- 添加了一个复制构造函数,以便在
DateAndTimeInfo
的另一个实例中将一个列表复制到另一个列表 - 添加了一个toString方法
String[] lines = {
"LSR2019-07-12_12:07:21.554",
"KMH2019-07-12_12:09:44.291",
"KMH2019-07-12_12:09:44.292",
"RGH2019-07-12_12:29:28.352",
"RGH2019-07-12_12:33:08.603",
"RGH2019-07-12_12:33:08.604"};
Function<String, LocalTime> toLT = (str) -> LocalTime
.from(DateTimeFormatter.ofPattern("HH:mm:ss.SSS")
.parse((str.substring(3).split("_")[1])));
Function<String, LocalDate> toLD = (str) -> LocalDate.parse(
str.substring(3).split("_")[0],
DateTimeFormatter.ofPattern("yyyy-MM-dd"));
Map<String, DateAndTimeInfo> map = lines
.collect(Collectors.toMap(
string -> string.substring(0,3),
string-> new DateAndTimeInfo(toLT.apply(string), toLD.apply(string)),
(dti1,dti2)-> dti1.copy(dti2)))
class DateAndTimeInfo {
private List<LocalTime> localTime = new ArrayList<>();
private List<LocalDate> localDate = new ArrayList<>();
public DateAndTimeInfo(LocalTime lt, LocalDate ld) {
localTime.add(lt);
localDate.add(ld);
}
public DateAndTimeInfo copy(DateAndTimeInfo dti) {
this.localTime.addAll(dti.localTime);
this.localDate.addAll(dti.localDate);
return this;
}
public String toString() {
return localTime.toString() + "n " + localDate.toString();
}
}
对于给定的测试数据,它会打印出来。
RGH=[12:29:28.352, 12:33:08.603, 12:33:08.604]
[2019-07-12, 2019-07-12, 2019-07-12]
KMH=[12:09:44.291, 12:09:44.292]
[2019-07-12, 2019-07-12]
LSR=[12:07:21.554]
[2019-07-12]
注意。您是否考虑创建如下地图:Map<String, List<DateAndTimeInfo>>
,并将每个类中的日期和时间作为字段存储?你可以用getter得到它们。这将是微不足道的实现。因此,键的值将是DateAndTimeInfo
对象的列表。
Map<String, List<DateAndTimeInfo>> map = lines
.collect(Collectors.groupingBy(str->str.substring(0,3),
Collectors.mapping(str->new DateAndTimeInfo(toLT.apply(str),
toLD.apply(str)), Collectors.toList())));