Skip to content

Instantly share code, notes, and snippets.

@cemolcay
Last active November 7, 2023 11:39
Show Gist options
  • Save cemolcay/83dc1e180d7e2a57302e1c384e39f4eb to your computer and use it in GitHub Desktop.
Save cemolcay/83dc1e180d7e2a57302e1c384e39f4eb to your computer and use it in GitHub Desktop.
Weighted Random Picker Swift
class WeightedRandom<T> {
var elements: [Element]
init(elements: [Element] = []) {
self.elements = elements
}
struct Element {
let item: T
let weight: Double
}
func randomElement() -> T? {
guard elements.count > 0 else { return nil }
// Create an array to store the cumulative sum of weights
var cumulativeWeights: [Double] = []
var totalWeight: Double = 0.0
// Calculate the cumulative sum of weights
for element in elements {
totalWeight += element.weight
cumulativeWeights.append(totalWeight)
}
// Generate a random number between 0 and the total weight
let randomValue = Double.random(in: 0..<totalWeight)
// Find the element that corresponds to the random value
var selectedElement: T?
for i in 0..<elements.count {
if randomValue <= cumulativeWeights[i] {
selectedElement = elements[i].item
break
}
}
return selectedElement
}
}
@cemolcay
Copy link
Author

cemolcay commented Nov 7, 2023

Usage:

let rand = WeightedRandom<String>(elements: [
    .init(item: "A", weight: 0.1),
    .init(item: "B", weight: 0.0),
    .init(item: "C", weight: 0.2),
    .init(item: "D", weight: 0.3),
    .init(item: "E", weight: 0.1),
])

for _ in 0..<20 {
    print(rand.randomElement()!)
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment