From df92a2c2d50fb20da732ed20ad3bf9365774e099 Mon Sep 17 00:00:00 2001 From: Andrew Lalis Date: Wed, 17 Apr 2019 23:42:37 +0200 Subject: [PATCH] Added correct algorithm! Yay! --- .../model/people/teams/Team.java | 2 +- .../team_importing/StudentTeamImporter.java | 103 +++++++++++++++++- 2 files changed, 101 insertions(+), 4 deletions(-) diff --git a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/model/people/teams/Team.java b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/model/people/teams/Team.java index 255883f..82a43f7 100644 --- a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/model/people/teams/Team.java +++ b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/model/people/teams/Team.java @@ -91,7 +91,7 @@ public abstract class Team

extends BasicEntity { public String toString() { StringBuilder sb = new StringBuilder(); for (P p : this.getMembers()) { - sb.append(p.toString()).append(", "); + sb.append(p.getFullName()).append(", "); } return sb.toString(); } diff --git a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/util/team_importing/StudentTeamImporter.java b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/util/team_importing/StudentTeamImporter.java index 0723148..774991d 100644 --- a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/util/team_importing/StudentTeamImporter.java +++ b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/util/team_importing/StudentTeamImporter.java @@ -11,7 +11,10 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Random; /** * Provides some methods to streamline the process of transforming a CSV file of student data into a list of valid teams @@ -33,19 +36,27 @@ public class StudentTeamImporter { List studentEntries = extractStudentsFromRecords(records); + System.out.println("<<< Entries (" + studentEntries.size() + ") >>>"); for (StudentRecordEntry entry : studentEntries) { System.out.println(entry.toString()); } - return new ArrayList<>(); + List studentTeams = generateTeamsFromStudentEntries(studentEntries, 0); + System.out.println("<<< Teams (" + studentTeams.size() + ") >>>"); + for (StudentTeam team : studentTeams) { + System.out.println("Team: " + team); + } + + return studentTeams; } /** * Extracts all student data from a list of records, and automatically discards outdated responses (those where the * same student submitted more than once). * @param records The list of records in the CSV file. - * @return A mapping for each timestamp to + * @return A list of all student entries. A student entry is an intermediate object used to organize the parsed data + * from each record in the CSV file. */ private static List extractStudentsFromRecords(Iterable records) { List studentEntries = new ArrayList<>(); @@ -73,7 +84,93 @@ public class StudentTeamImporter { return studentEntries; } + /** + * Generates a list of teams from a list of unique student entries. The algorithm is described as follows: + * + * 1. Select the next student from the list of entries. + * 2. If the student (A) has specified a partner (B), search for that partner (B) in the list of entries. + * 3. If the partner (B) also specified the student (A) as their preferred partner, a team is created from the two. + * a. Pop both student entries from the list of entries. + * 4. Else, place student (A) in a queue of single students. + * a. Pop student (A) from the list of entries. + * 5. If the list of entries is not empty, go to 1. + * 6. The list of entries is now empty, and zero or more entries exist in a queue of single students. + * 7. Pop two (or as many as possible) students randomly from the queue, and form a team from them. + * 8. Repeat until the queue of single students is empty. + * 9. There is now a list of student teams and no student should remain unprocessed. + * + * @param entries A list of record entries. + * @param seed A seed to use for randomization of single student teams. + * @return A list of student teams. + */ + private static List generateTeamsFromStudentEntries(List entries, long seed) { + List teams = new ArrayList<>(); + List singleStudentsEntryQueue = new ArrayList<>(); + Random random = new Random(seed); + // Realize step 5. Loop until there are no more processed entries. + while (!entries.isEmpty()) { + // Step 1. Select the next student from the list of entries. + StudentRecordEntry entry = entries.remove(0); + + // Step 2. If the student has a partner, search for that partner. + if (entry.hasPartner()) { + boolean partnerFound = false; // Use this to keep track of if a partner is actually found. + for (int i = 0; i < entries.size(); i++) { + StudentRecordEntry secondEntry = entries.get(i); + // Step 3. If the partner specifies their partner as the student (both want each other), then create a team. + if ( + entry.getPartnerStudent().equals(secondEntry.getStudent()) + && secondEntry.hasPartner() + && secondEntry.getPartnerStudent().equals(entry.getStudent()) + ) { + partnerFound = true; + + entries.remove(i); // Step 3a. The first student has been popped, so pop this one. + + StudentTeam team = new StudentTeam(); + team.addMember(entry.getStudent()); + team.addMember(secondEntry.getStudent()); + teams.add(team); + + break; + } + } + + // Step 4. If no partner was found, then add this entry to the queue of single students. + if (!partnerFound) { + singleStudentsEntryQueue.add(entry); + } + } else { + // Also Step 4. The student chose to have no partner, so add this entry to the queue of single students. + singleStudentsEntryQueue.add(entry); + } + } + + // We are now at step 6. + while (!singleStudentsEntryQueue.isEmpty()) { + StudentTeam team = new StudentTeam(); + StudentRecordEntry firstRandomEntry = singleStudentsEntryQueue.remove(random.nextInt(singleStudentsEntryQueue.size())); + team.addMember(firstRandomEntry.getStudent()); + + // Check if there's another student in the queue. + if (!singleStudentsEntryQueue.isEmpty()) { + StudentRecordEntry secondRandomEntry = singleStudentsEntryQueue.remove(random.nextInt(singleStudentsEntryQueue.size())); + team.addMember(secondRandomEntry.getStudent()); + } + + teams.add(team); + } + + return teams; + } + + /** + * Scans a list of student entries and removes entries which are outdated by newer entries by the same student, such + * that the resulting list contains only one unique entry per student. + * @param studentEntries The list of student entries, possibly containing duplicates. + * @return A list of student entries in which all outdated duplicates have been removed. + */ private static List removeDuplicateEntries(List studentEntries) { List uniqueStudentEntries = new ArrayList<>();