I have a collection of elements that I want to shuffle randomly, but every element has a different priority or weight. So the element with bigger weight has to have more pro
I have my solution but I think it can be improved:
module Utils
def self.random_suffle_with_weight(elements, &proc)
# Create a consecutive chain of element
# on which every element is represented
# as many times as its weight.
consecutive_chain = []
elements.each do |element|
proc.call(element).times { consecutive_chain << element }
end
# Choosine one element randomly from
# the consecutive_chain and remove it for the next round
# until all elements has been chosen.
shorted_elements = []
while(shorted_elements.length < elements.length)
random_index = Kernel.rand(consecutive_chain.length)
selected_element = consecutive_chain[random_index]
shorted_elements << selected_element
consecutive_chain.delete(selected_element)
end
shorted_elements
end
end
Test:
def test_random_suffle_with_weight
element_1 = { :id => "ID_1", :weight => 10 }
element_2 = { :id => "ID_2", :weight => 20 }
element_3 = { :id => "ID_3", :weight => 60 }
elements = [element_1, element_2, element_3]
Kernel.expects(:rand).with(90).returns(11)
Kernel.expects(:rand).with(70).returns(1)
Kernel.expects(:rand).with(60).returns(50)
assert_equal([element_2, element_1, element_3], Utils.random_suffle_with_weight(elements) { |e| e[:weight] })
end