In article 03fc01c2f5ba$a04cb8e0$0300a8c0@austin.rr.com,
Here’s a little question for you.
Given: A set of items, each with
an associated integer representing
the relative likelihood that each
item will be selected.
Write: A method that will select
a random item.
I’ve started this a couple of times,
but have become convinced I’m making
it too hard, and someone can probably
come up with a three-liner.
Any ideas?
You’re talking about some kind of proportional selection scheme (hey, you
wouldn’t happen to be working on Genetic Algorithms, would you?). One way
would be to do what’s called roulette wheel selection. You can visualize
a roulette wheel where each number is sized proportionally to the weight.
The bigger the weight, the more likely the ‘roulette wheel’ is to land on
that item.
It would look something like:
#Warning: untested code!
class RouletteWheel
def initialize(itemList)
@rouletteList =
runningTotal = 0
@items = itemList
calc_sum
@items.each_with_index{ |w,i|
prob = calc_prob(w)
runningTotal += prob
@rouletteList[i] = runningTotal
}
end
def spin
rn = rand
prev = 0.0
@items.each_with_index { |w,i|
@rouletteList.each_with_index { |p,j|
if rn.between?(prev,p)
return @items[j]
end
prev = p
}
}
#otherwise return the last one:
return @items[-1]
end
private
def calc_sum
@items.each { |w|
@sum += w
}
end
def calc_prob(value)
value/@sum.to_f
end
end
#use it:
rw = RouletteWheel([10,20,3,42,121,5])
item = rw.spin #most likely to get 121, least likely to get 3
Or alternatively, you could have spin return the index of the item in the
array.
Now of course you’d probably modify it so that the itemList passed in
isn’t just a list of integers, but objects which contain an integer
weighting…
Phil
···
Hal E. Fulton hal9000@hypermetrics.com wrote: