Algorithm to shuffle an Array randomly based on different weights

后端 未结 6 841
天涯浪人
天涯浪人 2021-01-19 14:19

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

6条回答
  •  死守一世寂寞
    2021-01-19 14:49

    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
    

提交回复
热议问题