Skip to content

Instantly share code, notes, and snippets.

@oeN
Last active Apr 29, 2020
Embed
What would you like to do?
Shuffle a Weighted array in Ruby
def weighted
a = []
(1..60).each do |i|
a << { value: "HIGH_#{i}", weight: 5 }
end
(1..30).each do |i|
a << { value: "MID_#{i}", weight: 3 }
end
(1..15).each do |i|
a << { value: "LOW_#{i}", weight: 2 }
end
a
end
def by_weight a, weight
a.select{ |el| el[:weight] == weight }
end
def sum_of_weights weighted
weighted.map{ |w| w[:weight] }.uniq.inject(:+).to_f
end
def probabilities weighted_array
sum_of_weights = sum_of_weights(weighted_array)
# initial probability
probability = 0.0
weights = weighted_array.map{ |w| w[:weight] }.uniq.sort
weights.map do |w|
current_probability = (w / sum_of_weights).round(3)
# sum the current_probability with the previous
probability += current_probability
{ weight: w, probability: probability }
end
end
def get_weight probabilities
r = rand
probabilities.each do |p|
return p[:weight] if r < p[:probability]
end
end
def run
# generate a weighted array
a = weighted
# calc the probabilities
probabilities = probabilities a
shuffle_weighted_array = []
10.times do
weight = get_weight probabilities
shuffle_weighted_array << by_weight(a, weight).sample[:value]
end
shuffle_weighted_array
end
sums = {
h: 0,
m: 0,
l: 0
}
1000.times do
a = run
sums[:h] += a.select{ |i| i[/^HIGH./] }.count
sums[:m] += a.select{ |i| i[/^MID./] }.count
sums[:l] += a.select{ |i| i[/^LOW./] }.count
end
# Prints the avarages of presence
p "HIGH AVG: #{sums[:h]/1000.0}"
p "MID AVG: #{sums[:m]/1000.0}"
p "LOW AVG: #{sums[:l]/1000.0}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment