Weighted random selection





7
Date Submitted Thu. Nov. 2nd, 2006 1:49 AM
Revision 1 of 1
Scripter SCoon
Tags List | Random | Ruby
Comments 1 comments
Weighted random selection from the list.

Don't forget to call itemsChanged after updating list content.
class RandomItemSelector

  def initialize(items, weightFunc)
    @weightFunc = weightFunc
    @items = items
    @totalWeight = nil
  end

  def next
    target = rand(totalWeight)
    min = 0
    @items.each { |item|
      max = min + @weightFunc.call(item)
      if min <= target && target < max
        return item;
      end
      min = max
    }
    raise "Internal error: can't select random item"
  end

  def itemsChanged
    @totalWeight =  nil
  end

  def totalWeight
    if @totalWeight.nil?
      @totalWeight = 0
      @items.each { |item| @totalWeight += @weightFunc.call(item) }
    end
    return @totalWeight
  end
 
end
items = []
for i in 1..100
  items.push case rand(3)
    when 0
      'Red'
    when 1
      'Green'
    when 2
      'Blue'
    end
end

selector = RandomItemSelector.new(items, proc { |item|
  case item
    when 'Red'
      10
    when 'Green'
      5
    when 'Blue'
      1
  end
})

for i in 1..20
  print selector.next
  print " "
end

Vladislav Zlobin

Comments

Comments See also
Thu. Nov. 2nd, 2006 3:52 AM    Scripter SCoon

Voting