I was asked a weighted probability question in a technical interview a few months ago that went something like this:
Given an input of colors and an integer "weight" value, randomly return a color based on its weight.
The sample input would be something like this:
[("Red", 20), ("Blue", 50), ("Green", 70)]
The probability that each color would be returned would be something like:
Red: 20/140
Blue: 50/140
Green: 70/140
(where 140 is the sum of the weight of the input colors)
I was thinking about this recently and decided to give it another go in Swift.
My first pass was:
func weightedColor(input: [(String, Int)]) -> String {
var total = 0
for tuple in input {
total += tuple.1
}
let rand = Int(arc4random_uniform(UInt32(total)))
var sum = 0
for tuple in input {
let range = sum + tuple.1
if rand <= range {
return tuple.0
} else {
sum += tuple.1
}
}
return ""
}
Then I realized I could optimize the total weight calculation with map-reduce:
let total = UInt32(input.map { $0.1 }.reduce(0, combine: +))
My current implementation is as follows:
func weightedColor(input: [(String, Int)]) -> String {
let total = UInt32(input.map { $0.1 }.reduce(0, combine: +))
let rand = Int(arc4random_uniform(total))
var sum = 0
for tuple in input {
let range = sum + tuple.1
if rand <= range {
return tuple.0
} else {
sum += tuple.1
}
}
return ""
}
I don't like the for tuple in input
loop and feel it can be optimized further. How can I improve this answer?