Last active
September 25, 2015 23:47
-
-
Save danfishgold/4e2116aa7d680b42db30 to your computer and use it in GitHub Desktop.
My dirty 2:30 AM solution for the Omni Group’s Swift Bike Shedding Club week two question: http://rubyquiz.com/quiz2.html (via Brent)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
sort families by their size. (let's name them A, B, C, D, and E.) | |
(if the biggest family is over half of the enitre group there's no valid solution.) | |
while A.count > B.count | |
pair up santas from A (the biggest family) and E (the smallest) | |
(e.g., Dan A is Brent E's santa and vice versa) | |
while there are still unmatched people | |
make loops of people | |
(e.g., Alex A is Brian B's santa. Brian is Clair C's santa, ..., and Eric E is Alex A's santa) | |
After each step of new santas make sure the smallest family isn't empty. | |
If it is empty just throw it out and treat the next one (D) as the smallest. | |
*/ | |
import Foundation | |
struct Person: Hashable, CustomStringConvertible { | |
var firstName: String | |
var lastName: String | |
init(_ name: String) { | |
let nameParts = name.componentsSeparatedByString(" ") | |
self.firstName = nameParts[0] | |
self.lastName = nameParts[1] | |
} | |
var description: String { | |
return "\(firstName) \(lastName)" | |
} | |
var hashValue: Int { | |
return description.hashValue | |
} | |
} | |
func ==(lhs: Person, rhs: Person) -> Bool { | |
return lhs.hashValue == rhs.hashValue | |
} | |
func tally<T, S: Hashable>(array: [T], key: T -> S) -> [S: [T]] { | |
var res: [S: [T]] = [:] | |
for element in array { | |
let k = key(element) | |
res[k] = (res[k] ?? []) + [element] | |
} | |
return res | |
} | |
func findSantas(people: [Person]) -> [Person: Person]? { | |
// Tally by last name, sort by family size. | |
var families = tally(people, key: { person in person.lastName }).values.sort({ $0.count > $1.count }) | |
// Verify that the biggest family isn't too big. | |
guard !families.isEmpty && families.first!.count <= people.count/2 else { return nil } | |
var santas: [Person: Person] = [:] | |
while families[0].count > families[1].count { | |
let p1 = families[0].removeLast() | |
let p2 = families[families.count-1].removeLast() | |
santas[p1] = p2 | |
santas[p2] = p1 | |
if families.last?.isEmpty ?? false { | |
families.removeLast() | |
} | |
} | |
while !families.isEmpty { | |
var previousGuy = families.last!.last! | |
for i in 0..<families.count { | |
let newGuy = families[i].removeLast() | |
santas[previousGuy] = newGuy | |
previousGuy = newGuy | |
} | |
while families.last?.isEmpty ?? false { | |
families.removeLast() | |
} | |
} | |
return santas | |
} | |
let people1 = [Person("Luke Skywalker"), Person("Leia Skywalker"), Person("Toula Portokalos"), Person("Gus Portokalos"), Person("Bruce Wayne"), Person("Virgil Brigman"), Person("Lindsey Brigman"), Person("Franz Kafka"), Person("Courtney Kafka"), Person("Skip Kafka"), Person("Aloysius Kafka")] | |
let people2 = [Person("Luke Skywalker"), Person("Leia Skywalker"), Person("Toula Portokalos")] | |
print("Solution exists: \(findSantas(people1))") // valid | |
print("Solution doesn't exist: \(findSantas(people2))") // returns nil |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment