Java 8 api流.需要解决重复密钥问题



我有一个日志文件,如下所示:

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())));

最新更新