Reputation: 729
Say I have a method that takes an array of objects, each with a percentage attribute controlling how often the element is returned by the method
Ie. I want to be able to add an object to an array E, with percentage attribute 0.20 and have it returned approximately every fifth method call. What would be the best way to implement such a method?
PS. Not just have an array of 5 objects and select one at random
Upvotes: 2
Views: 907
Reputation: 9344
Maybe something like this?
class Sample
def initialize(e)
@E = e
@sums = []
@E.each_with_index { |x, i| @sums << (@sums.last || 0) + @E[i][:pct] }
end
def draw
rand = Random.rand()
for i in 0..(@sums.length-1)
return @E[i][:el] if rand <= @sums[i]
end
end
end
ss = Sample.new(e = [{el: "hello", pct: 0.3}, {el: "world", pct: 0.3}, {el: "goodbye", pct: 0.4}])
# Draw "hello" with 30%, "world" with 30%, "goodbye" with 40% probability, respectively
results = []
10_000.times { results << ss.draw }
e.map { |x| { x[:el] => results.count { |y| y == x[:el] }.to_f / results.length } }.reduce(:merge)
# observed percentages of 10,000 draws
# {"hello"=>0.2938, "world"=>0.3046, "goodbye"=>0.4016}
Upvotes: 3