使用Stream API查找相同的日期并计算对象



我需要一些关于Stream API的帮助。我需要根据位置对对象列表进行分组,如果位置相同但日期不同而与时间无关,则将计数增加1。我已经为类提供了下面的代码,其中包含getterssetter和数据以及预期的输出。

public class Event {
String location;
String date;
String count; 

public String getCount() {
return count;
}
public void setCount(String count) {
this.count = count;
}
public String getLocation() {
return location;
}
public String getDate() {
return date;
}
public void setLocation(String location) {
this.location = location;
}
public void setDate(String date) {
this.date = date;
}
} 

事件类别的数据:

Event event = new Event();

event.setLocation("98.55.62.162");
event.setDate("09/17/2022 12:05:43 PM");
event.add(event);
event.setLocation("98.55.62.162");
event.setDate("09/16/2022 12:05:45 PM");
event.add(event);
event.setLocation("98.55.62.162");
event.setDate("09/16/2022 12:05:47 PM");
event.add(event);
event.setLocation("98.55.62.162");
event.setDate("09/15/2022 12:05:49 PM");
event.add(event);
event.setLocation("98.55.62.163");
event.setDate("09/17/2022 12:05:31 PM");
event.add(event);
event.setLocation("98.55.62.163");
event.setDate("09/16/2022 12:05:22 PM");
event.add(event);
event.setLocation("98.55.62.163");
event.setDate("09/16/2022 12:05:11 PM");
event.add(event);

我试着制作Map<String, List<Event>>

Map<String, List<Event>> eventMap = events.stream().collect(Collectors.groupingBy(s -> s.getLocation()));

它对我不起作用。
我需要像这样的输出映射<字符串,整数>映射,其中String是位置,计数基于Date。如果日期不同,则将计数增加1。时间在这里并不重要。我不知道如何使用流API或for循环对它们进行分组。

o/p: ["98.55.62.162":3 , "98.55.62.163":2]

这是可能的,但有点棘手。检查此

Event event = new Event();
List<Event> events = new ArrayList<>();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/d/yyyy hh:mm:ss a");
event.setLocation("98.55.62.162");
event.setDate(LocalDate.parse("09/17/2022 12:05:43 PM", formatter));
events.add(event);
event = new Event();
event.setLocation("98.55.62.162");
event.setDate(LocalDate.parse("09/16/2022 12:05:45 PM", formatter));
events.add(event);
event = new Event();
event.setLocation("98.55.62.162");
event.setDate(LocalDate.parse("09/16/2022 12:05:47 PM", formatter));
events.add(event);
event = new Event();
event.setLocation("98.55.62.162");
event.setDate(LocalDate.parse("09/15/2022 12:05:49 PM", formatter));
events.add(event);
event = new Event();
event.setLocation("98.55.62.163");
event.setDate(LocalDate.parse("09/17/2022 12:05:31 PM", formatter));
events.add(event);
event = new Event();
event.setLocation("98.55.62.163");
event.setDate(LocalDate.parse("09/16/2022 12:05:22 PM", formatter));
events.add(event);
event = new Event();
event.setLocation("98.55.62.163");
event.setDate(LocalDate.parse("09/16/2022 12:05:11 PM", formatter));
events.add(event);
Map<String, Long> eventMap = events
.stream()
.collect(
Collectors.groupingBy(Event::getLocation)
).entrySet()
.stream()
.collect(Collectors.toMap(
Map.Entry::getKey, v -> v.getValue()
.stream()
.map(e -> e.getDate())
.distinct()
.count()));

此答案基于Demian的答案。我做了以下更改:

  1. Locale.ENGLISHDateTimeFormatter一起使用,这对于日期时间值不是强制性的,但强烈建议使用,因为API的日期时间格式化/解析对Locale敏感
  2. 保持Event#date的类型为String,而我建议您在构造Event对象时使用LocalDateTime并解析字符串日期时间字符串,就像Demian在回答中所做的那样。如果天、月、年、小时、分钟等有单独的值,则可以使用LocalDateTime#of方法之一填充Event#date
  3. .map(e -> LocalDateTime.parse(e.getDate(), formatter).toLocalDate())的使用:在这个映射中,我首先将Event#date解析为LocalDateTime,然后使用LocalDateTime#toLocalDate仅提取日期部分
List<Event> events = new ArrayList<>();

Event event = new Event();
event.setLocation("98.55.62.162");
event.setDate("09/17/2022 12:05:43 PM");
events.add(event);

...
...
...

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd/yyyy hh:mm:ss a", Locale.ENGLISH);

Map<String, Long> eventMap = events
.stream()
.collect(
Collectors.groupingBy(Event::getLocation))
.entrySet()
.stream()
.collect(Collectors.toMap(
Map.Entry::getKey, v -> v.getValue()
.stream()
.map(e -> LocalDateTime.parse(e.getDate(), formatter).toLocalDate())
.distinct()
.count()));

System.out.println(eventMap);

输出

{98.55.62.163=2, 98.55.62.162=3}

跟踪:日期时间了解有关现代日期时间API的更多信息。

最新更新