Weighted Shuffle in Elixir
Shuffling a list is easy, but what if you want to perform a weighted shuffle? That is, what if some elements in a list had a greater chance of being selected, or higher in the list, than others?
Given these colors and these weights:
weighted_colors = [{1, "orange"}, {3, "green"}, {5, "red"}]
I can create a list that is mostly represents each item the number of times of it's weight by utilizing List.duplicate
:
weighted_colors
|> Enum.map(fn ({weight, color}) ->
List.duplicate(color, weight)
end)
|> Enum.flatten
# ["orange", "green", "green", "green", "red", "red", "red", "red", "red"]
Then shuffle it:
|> Enum.shuffle
# ["red", "red", "orange", "red", "green", "green", "red", "green", "red"]
And then use Enum.uniq
attribute of preserving the order in which it encounters each unique element from left to right.
|> Enum.uniq
# ["red", "orange", "green"]
Run this 100 times over the same weighted list and the most outcome that you would experience most often is:
# ["red", "green", "orange"]
Tweet