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]
CodePudding user response:
it is possible but kind of tricky. Check this
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()));
CodePudding user response:
This answer is based on the answer by Demian. I have made the following changes:
- Use of
Locale.ENGLISH
withDateTimeFormatter
which is not mandatory for your date-time values but is highly recommended because the date-time formatting/parsing API isLocale
-sensitive. - Keeping the type of
Event#date
asString
while I recommend you useLocalDateTime
and parse the string date-time string while constructingEvent
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 ofLocalDateTime#of
methods to populateEvent#date
. - Use of
.map(e -> LocalDateTime.parse(e.getDate(), formatter).toLocalDate())
: In this mapping, I have first parsedEvent#date
intoLocalDateTime
and then extracted just the date part by usingLocalDateTime#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.