-
Notifications
You must be signed in to change notification settings - Fork 0
Optional attendees #9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,6 +14,7 @@ | |
|
|
||
| package com.google.sps; | ||
|
|
||
| import com.google.common.collect.Sets; | ||
| import java.util.Collection; | ||
| import java.util.Collections; | ||
| import java.util.HashSet; | ||
|
|
@@ -23,6 +24,9 @@ | |
| import java.util.List; | ||
|
|
||
| public final class FindMeetingQuery { | ||
| // Returns available meetings for day given events and request. query will return a list of TimeRanges including optional attendees | ||
| // if there is availability with optional attendees, and will otherwise return a list of TimeRanges for only required attendees. Returns | ||
| // an empty List object if there is no availability. | ||
| public Collection<TimeRange> query(Collection<Event> events, MeetingRequest request) { | ||
| // In this case, long to int conversion is safe because duration can never exceed 2^32. Leaving duration as long | ||
| // leads to compile errors. | ||
|
|
@@ -34,23 +38,73 @@ public Collection<TimeRange> query(Collection<Event> events, MeetingRequest requ | |
| } | ||
|
|
||
| // Seperate relevant TimeRanges from events, put into ArrayList and sort by ascending meeting start time | ||
| // Optional attendees are handled by running two sets of queries in parallel: a query if we are including optional attendees, | ||
| // and a query if we are only considering required attendees. If the optional attendee query is empty, then that means that | ||
| // there are no valid times if we include optional attendees, and optional attendees are ignored. | ||
| List<TimeRange> attendedMeetings = new ArrayList<>(); | ||
| List<TimeRange> allAttendedMeetings = new ArrayList<>(); | ||
|
|
||
| // Attendees is only required attendees, allAttendees includes optional attendees | ||
| Set<String> requiredAttendees = new HashSet<>(request.getAttendees()); | ||
| Set<String> optionalAttendees = new HashSet<>(request.getOptionalAttendees()); | ||
|
|
||
| for (Event event : events) { | ||
| // First check if the event in question contains people from request, add those meetings to attendedMeetings | ||
| Set<String> attendees = new HashSet<>(request.getAttendees()); | ||
| attendees.retainAll(event.getAttendees()); | ||
| Set<String> allAttendees = new HashSet<>(Sets.union(requiredAttendees, optionalAttendees)); | ||
|
|
||
| requiredAttendees.retainAll(event.getAttendees()); | ||
| allAttendees.retainAll(event.getAttendees()); | ||
|
|
||
| if (!attendees.isEmpty()){ | ||
| if (!requiredAttendees.isEmpty()){ | ||
| attendedMeetings.add(event.getWhen()); | ||
| } | ||
|
|
||
| if (!allAttendees.isEmpty()) { | ||
| allAttendedMeetings.add(event.getWhen()); | ||
| } | ||
|
|
||
| } | ||
|
|
||
| // Sort attendedMeetings so that we can filter out all nested meetings in next step | ||
| Collections.sort(attendedMeetings, TimeRange.ORDER_BY_START); | ||
| Collections.sort(allAttendedMeetings, TimeRange.ORDER_BY_START); | ||
|
|
||
| // All openings represents the availabilities WITH optional attendees, requiredOpenings represents only required attendees. | ||
| // if allOpenings is empty, that means that there is a conflict with optional attendees and optional attendees should be ignored. | ||
| List<TimeRange> requiredOpenings = new ArrayList<>(findOpenings(attendedMeetings, duration)); | ||
| List<TimeRange> allOpenings = new ArrayList<>(findOpenings(allAttendedMeetings, duration)); | ||
|
|
||
| // As-is, the user will not be aware whether this function is returning allOpenings or requiredOpenings. As-is, the function | ||
| // simply returns whichever is available. | ||
| return allOpenings.size() == 0 ? requiredOpenings : allOpenings; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add a good comment in the method header on what it returns ("if there is an opening for eveyone, return it, otherwise return the opening for the required").
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Made explicit in a comment. I definitely understand your concerns, and will revisit further if you'd like |
||
| } | ||
|
|
||
| // Takes in sorted list of meetings and returns next available TimeRange given, or null if none available with current startTime | ||
| private TimeRange findNextTime(List<TimeRange> meetings, int startMeetingIndex, int duration) { | ||
| int startTime = meetings.get(startMeetingIndex).end(); | ||
|
|
||
| List<TimeRange> validMeetings = new ArrayList<>(); | ||
| // If this is the last meeting in the list and there's a meeting time that fits, return a meeting time. | ||
| if (startMeetingIndex == meetings.size() - 1) { | ||
| return (startTime + duration <= TimeRange.END_OF_DAY) ? | ||
| TimeRange.fromStartEnd(startTime, TimeRange.END_OF_DAY, true) | ||
| : null; | ||
| } | ||
|
|
||
| for (TimeRange meeting : attendedMeetings) { | ||
| // If next meeting's start time is farther away than duration, | ||
| // return a TimeRange from startTime -> the start of the next meeting. | ||
| if (meetings.get(startMeetingIndex + 1).start() - startTime >= duration) { | ||
| return TimeRange.fromStartEnd(startTime, meetings.get(startMeetingIndex + 1).start(), false); | ||
| } | ||
| else { | ||
| return null; | ||
| } | ||
| } | ||
|
|
||
| // Takes in sorted list of TimeRanges, filters out nested meetings, and then passes into findNextTime | ||
| private List<TimeRange> findOpenings(List<TimeRange> meetings, int duration) { | ||
| List<TimeRange> validMeetings = new ArrayList<>(); | ||
|
|
||
| for (TimeRange meeting : meetings) { | ||
|
|
||
| int numMeetings = validMeetings.size(); | ||
|
|
||
|
|
@@ -85,25 +139,4 @@ public Collection<TimeRange> query(Collection<Event> events, MeetingRequest requ | |
|
|
||
| return openings; | ||
| } | ||
|
|
||
| // Takes in sorted list of meetings and returns next available TimeRange given, or null if none available with current startTime | ||
| private TimeRange findNextTime(List<TimeRange> meetings, int startMeetingIndex, int duration) { | ||
| int startTime = meetings.get(startMeetingIndex).end(); | ||
|
|
||
| // If this is the last meeting in the list and there's a meeting time that fits, return a meeting time. | ||
| if (startMeetingIndex == meetings.size() - 1) { | ||
| return (startTime + duration <= TimeRange.END_OF_DAY) ? | ||
| TimeRange.fromStartEnd(startTime, TimeRange.END_OF_DAY, true) | ||
| : null; | ||
| } | ||
|
|
||
| /* If next meeting's start time is farther away than duration, | ||
| * return a TimeRange from startTime -> the start of the next meeting. */ | ||
| if (meetings.get(startMeetingIndex + 1).start() - startTime >= duration) { | ||
| return TimeRange.fromStartEnd(startTime, meetings.get(startMeetingIndex + 1).start(), false); | ||
| } | ||
| else { | ||
| return null; | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You cannot take out requiredAttendees because you eventually changes them bellow (retainAll). That reminds me of a lesson that you want to make objects immutable whenever possible. Can you move the requiredAttendees back in and make optionalAttendees ImmutableSet?
Also try to find out other immutable containers throughout the code and change them to immutable.