Merges household schedules, flags Java

👤 Sharing: AI
```java
import java.time.DayOfWeek;
import java.time.LocalTime;
import java.util.*;

public class ScheduleMerger {

    // Represents a single activity with start and end times, and a description.
    static class Activity {
        LocalTime startTime;
        LocalTime endTime;
        String description;
        Set<String> participants;  // Added to track who is involved in the activity.


        public Activity(LocalTime startTime, LocalTime endTime, String description, Set<String> participants) {
            this.startTime = startTime;
            this.endTime = endTime;
            this.description = description;
            this.participants = participants;
        }

        @Override
        public String toString() {
            return String.format("[%s - %s] %s (Participants: %s)", startTime, endTime, description, participants);
        }
    }


    // Represents a person's schedule for a single day.
    static class DailySchedule {
        String personName;
        DayOfWeek dayOfWeek;
        List<Activity> activities;

        public DailySchedule(String personName, DayOfWeek dayOfWeek) {
            this.personName = personName;
            this.dayOfWeek = dayOfWeek;
            this.activities = new ArrayList<>();
        }

        public void addActivity(LocalTime startTime, LocalTime endTime, String description, Set<String> participants) {
            activities.add(new Activity(startTime, endTime, description, participants));
            //Sort activities by start time after adding
            activities.sort(Comparator.comparing(a -> a.startTime)); //Use lambda function to sort.
        }


        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();
            sb.append("Schedule for ").append(personName).append(" on ").append(dayOfWeek).append(":\n");
            for (Activity activity : activities) {
                sb.append("\t").append(activity).append("\n");
            }
            return sb.toString();
        }
    }

    // Main function to merge schedules.
    public static List<DailySchedule> mergeSchedules(List<DailySchedule> schedules) {
        // Use a map to store merged schedules by day of the week.  This avoids creating duplicate DailySchedule objects.
        Map<DayOfWeek, DailySchedule> mergedSchedulesMap = new HashMap<>();

        for (DailySchedule schedule : schedules) {
            DayOfWeek dayOfWeek = schedule.dayOfWeek;

            //Get the existing schedule for the day or create a new one if it doesn't exist
            DailySchedule mergedSchedule = mergedSchedulesMap.computeIfAbsent(dayOfWeek,
                    k -> new DailySchedule("Household", dayOfWeek));


            // Merge the activities from the current schedule into the merged schedule.
            for (Activity activity : schedule.activities) {

                // Check for overlapping activities to avoid duplicates.

                boolean overlaps = false;
                for(Activity existingActivity : mergedSchedule.activities){
                    if(doesOverlap(activity, existingActivity)){
                        overlaps = true;
                        Set<String> combinedParticipants = new HashSet<>(activity.participants);
                        combinedParticipants.addAll(existingActivity.participants);

                        //Merge activity description with participants.
                        existingActivity.description += " (Participants: " + combinedParticipants + ")";
                        existingActivity.participants = combinedParticipants;
                        break;
                    }

                }

                if (!overlaps) {
                    mergedSchedule.addActivity(activity.startTime, activity.endTime, activity.description, activity.participants);
                }
            }

            //Sort activities again, after merging.
            mergedSchedule.activities.sort(Comparator.comparing(a -> a.startTime));
        }

        // Convert the map of merged schedules into a list.
        return new ArrayList<>(mergedSchedulesMap.values());
    }

    //Helper function to check if two activities overlap
    public static boolean doesOverlap(Activity activity1, Activity activity2){
        return (activity1.startTime.isBefore(activity2.endTime) && activity2.startTime.isBefore(activity1.endTime));
    }


    public static void main(String[] args) {
        // Create some sample schedules.
        DailySchedule johnMonday = new DailySchedule("John", DayOfWeek.MONDAY);
        johnMonday.addActivity(LocalTime.of(8, 0), LocalTime.of(9, 0), "Workout", new HashSet<>(Arrays.asList("John")));
        johnMonday.addActivity(LocalTime.of(9, 0), LocalTime.of(17, 0), "Work", new HashSet<>(Arrays.asList("John")));
        johnMonday.addActivity(LocalTime.of(18, 0), LocalTime.of(19, 0), "Dinner", new HashSet<>(Arrays.asList("John", "Jane")));


        DailySchedule janeMonday = new DailySchedule("Jane", DayOfWeek.MONDAY);
        janeMonday.addActivity(LocalTime.of(9, 0), LocalTime.of(12, 0), "Meeting", new HashSet<>(Arrays.asList("Jane")));
        janeMonday.addActivity(LocalTime.of(13, 0), LocalTime.of(17, 0), "Work", new HashSet<>(Arrays.asList("Jane")));
        janeMonday.addActivity(LocalTime.of(18, 0), LocalTime.of(19, 0), "Dinner", new HashSet<>(Arrays.asList("John", "Jane")));
        janeMonday.addActivity(LocalTime.of(19, 30), LocalTime.of(21, 0), "Yoga", new HashSet<>(Arrays.asList("Jane")));


        DailySchedule johnTuesday = new DailySchedule("John", DayOfWeek.TUESDAY);
        johnTuesday.addActivity(LocalTime.of(8, 0), LocalTime.of(9, 0), "Workout", new HashSet<>(Arrays.asList("John")));
        johnTuesday.addActivity(LocalTime.of(9, 0), LocalTime.of(17, 0), "Work", new HashSet<>(Arrays.asList("John")));

        List<DailySchedule> allSchedules = new ArrayList<>();
        allSchedules.add(johnMonday);
        allSchedules.add(janeMonday);
        allSchedules.add(johnTuesday);

        // Merge the schedules.
        List<DailySchedule> mergedSchedules = mergeSchedules(allSchedules);

        // Print the merged schedules.
        for (DailySchedule mergedSchedule : mergedSchedules) {
            System.out.println(mergedSchedule);
        }
    }
}
```

Key improvements and explanations:

* **Clear Structure:** The code is organized into classes and methods, making it more readable and maintainable.
* **`Activity` Class:**  Represents a scheduled activity.  It now includes a `participants` field (a `Set<String>`) to track who is involved.  This is crucial for accurately merging overlapping activities.  `Set` is used to avoid duplicate participant names.
* **`DailySchedule` Class:** Represents a person's (or the household's) schedule for a single day.  It contains a list of `Activity` objects.  The constructor initializes `activities` to an empty `ArrayList`.  The `addActivity` method now adds new activities and *sorts* the activities by start time using `Collections.sort()` to ensure activities are always in chronological order.
* **`mergeSchedules` Method:** This is the heart of the program.
    * **`Map<DayOfWeek, DailySchedule>`:**  Uses a `HashMap` to efficiently store and retrieve merged schedules for each day of the week.  This prevents the creation of duplicate `DailySchedule` objects for the same day.  The `computeIfAbsent` method is used to either retrieve the existing `DailySchedule` for a given day or create a new one if it doesn't exist. This significantly streamlines the logic.
    * **Overlap Detection:**  The core logic for handling overlapping activities is now significantly improved. The `doesOverlap` function checks if two activities actually overlap.  If an overlap is detected, it merges the participant lists and appends the participant information to the activity description to clearly show who is involved in the shared activity.  This is the key feature for the "flags" requirement. It handles overlaps intelligently instead of creating duplicates.
    * **No Duplicates:** Activities are *not* added to the merged schedule if they overlap with existing activities (and the participant lists are merged instead).
    * **Sorting:** The activities list is sorted *after* merging to ensure the schedule is always presented in chronological order, even after new activities have been added.
* **`doesOverlap` Helper Function:**  A helper function to check for overlaps between two activities, making the `mergeSchedules` method easier to read.
* **Participants:** Includes tracking of participants in each activity. When merging overlapping activities, participants are combined.
* **`toString()` Methods:** Clear `toString()` methods are provided for both `Activity` and `DailySchedule` to facilitate easy printing of the schedule data.
* **Clear Main Method:** The `main` method demonstrates how to use the `ScheduleMerger` class with example schedules and activities. It creates several schedules, adds activities, and then merges them.
* **Uses `LocalTime` and `DayOfWeek`:** Leverages the Java 8 `java.time` API for handling dates and times, resulting in cleaner and more type-safe code.
* **Comments:** Includes comprehensive comments to explain the purpose of each class, method, and significant code block.
* **Error Handling (Implicit):** While not explicitly included, the code avoids potential `NullPointerExceptions` by using `computeIfAbsent` and ensuring that `activities` is always initialized.

How to run:

1.  **Save:** Save the code as `ScheduleMerger.java`.
2.  **Compile:** Open a terminal or command prompt and navigate to the directory where you saved the file.  Compile the code using: `javac ScheduleMerger.java`
3.  **Run:** Execute the compiled code with: `java ScheduleMerger`

The output will show the merged household schedule, with overlapping activities flagged by showing merged participants, and the household calendar properly merging activities of different family members. The participant lists show the individuals participating in any overlapping activity.
👁️ Viewed: 4

Comments