I need some help with the Stream API. I need to group a list of objects based on location and if location is same but date is different irrespective of time then increment count by 1. I have provided below code for class with getters setters and data and expected output.
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;
}
}
Data for Event Class:
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);
I tried to make Map<String, List<Event>>
Map<String, List<Event>> eventMap = events.stream().collect(Collectors.groupingBy(s -> s.getLocation()));
It's not working for me.
I need output like
Map<String,Integer> map where String is location and count is based on Date. If date is different then increment count by 1. Time is not important here.
I am not sure how to group them using stream API or for loop.
o/p: ["98.55.62.162":3 , "98.55.62.163":2]
This answer is based on the answer by Demian. I have made the following changes:
Locale.ENGLISH
with DateTimeFormatter
which is not mandatory for your date-time values but is highly recommended because the date-time formatting/parsing API is Locale
-sensitive.Event#date
as String
while I recommend you use LocalDateTime
and parse the string date-time string while constructing Event
objects, the way Demian has done in his answer. If you have separate values for day, month, year, hour, minute etc., you can use one of LocalDateTime#of
methods to populate Event#date
..map(e -> LocalDateTime.parse(e.getDate(), formatter).toLocalDate())
: In this mapping, I have first parsed Event#date
into LocalDateTime
and then extracted just the date part by using 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);
Output:
{98.55.62.163=2, 98.55.62.162=3}
Learn more about the the modern date-time API from Trail: Date Time.