Deterministic Secret Santa Assignment
Problem statement
A holiday gift exchange randomly assigns each person in a group one other person to buy a gift for. Everyone must both give and receive exactly one gift, and nobody may be assigned to themself.
You are given a matrix participants, parsed from a CSV file. Each row is [name, email], optionally followed by an exclusion list: the names of people this person cannot receive a gift from. A row such as ["DDD", "d@x", "AAA", "BBB"] means DDD refuses gifts from AAA and BBB. Exclusions go one way only. A single empty string after the email means the list is empty, which is how a trailing comma in the file looks. Names in a list match exactly, including letter case.
So that every run gives the same answer, build the assignment in this fixed way:
- Sort the participants by email address in ascending lexicographic order.
- Go through the sorted participants as givers, in order. Each giver first considers the next participant in the sorted order, then the one after that, wrapping around from the last participant to the first, and stopping before reaching themself.
- The giver takes the first person they consider who has no giver yet, who does not refuse this giver, and who still leaves a way to give every remaining giver a valid recipient.
Return a matrix whose rows are [giverEmail, recipientEmail], in ascending order of giverEmail. If no complete assignment exists, return an empty matrix.
Function
assignSecretSanta(participants: String[][]) → String[][]Examples
Example 1
participants = [["Mina","mina@example.com"],["Ari","ari@example.com"],["Zoe","zoe@example.com"]]return = [["ari@example.com","mina@example.com"],["mina@example.com","zoe@example.com"],["zoe@example.com","ari@example.com"]]Nobody has an exclusion list. In email order, each person gives to the next person: ari to mina, mina to zoe, and the last person, zoe, wraps around to ari.
Example 2
participants = [["Ben","b@shop.test"],["Ana","a@shop.test"]]return = [["a@shop.test","b@shop.test"],["b@shop.test","a@shop.test"]]With two people and no exclusion lists, each one gives to the other.
Example 3
participants = [["Kai","kai@x.dev"],["Kai","a@x.dev"],["Lee","m@x.dev"],["Rae","z@x.dev"]]return = [["a@x.dev","kai@x.dev"],["kai@x.dev","m@x.dev"],["m@x.dev","z@x.dev"],["z@x.dev","a@x.dev"]]Names do not decide the order; unique email addresses do. The two people named Kai are still separate people.
Example 4
participants = [["AAA","aaa@example.com"],["BBB","bbb@example.com","AAA"],["CCC","ccc@example.com",""],["DDD","ddd@example.com","AAA","BBB","CCC"],["EEE","eee@example.com","AAA","DDD"]]return = [["aaa@example.com","ccc@example.com"],["bbb@example.com","eee@example.com"],["ccc@example.com","aaa@example.com"],["ddd@example.com","bbb@example.com"],["eee@example.com","ddd@example.com"]]DDD refuses AAA, BBB, and CCC, so only EEE can give to DDD. AAA cannot give to BBB, because BBB refuses AAA, so AAA takes CCC, which still leaves a complete assignment. BBB skips the taken CCC and the refusing DDD, and takes EEE. CCC skips DDD and the taken EEE, and takes AAA. DDD skips EEE, which refuses it, and the taken AAA, and takes BBB. EEE gets the only person left, DDD.
Example 5
participants = [["Ann","a@x.dev","Ben","Cam"],["Ben","b@x.dev"],["Cam","c@x.dev"]]return = []Ann refuses both other people, and nobody may give to themself, so nobody can give to Ann. No complete assignment exists, so the answer is empty.
Constraints
2 <= participants.length <= 602 <= participants[i].length <= participants.length + 1- Every name and email is a non-empty ASCII string of at most
100characters. - All email addresses are unique.
- Each name in an exclusion list is the name of exactly one other participant, and a list has no repeats. A list may instead be one empty string.