```"Hal E. Fulton" <hal9000 / hypermetrics.com> wrote in message news:<03fc01c2f5ba\$a04cb8e0\$0300a8c0 / austin.rr.com>...
> 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.

It's not exactly what you want (but there are good reasons for it
being different), but here's the code I've been using for ages:

module WeightedRand

def select
p = rand
each do |prob, value|
return value if p < prob
p -= prob
end
nil
end

end

a = [[0.5, :heads], [0.5, :tails]].extend(WeightedRand)
5.times { puts(a.select) }

The list of items is an Array of [Probability, Value] pairs. This
means that you don't have to compute the sum (i.e. normalise the
probabilities) each time you select something (good if you need to do
lots of selects).

Here's some more code:

module WeightedRand

# Normalise probabilities
def normalize!
sum = 0.0
each do |prob, value|
sum += prob
end
unless sum.zero?
collect! do |prob, value|
[prob / sum, value]
end
end
end

# Equal probabilities
def uniform!
p = 1.0 / size
collect! do |prob, value|
[p, value]
end
end

end

# Convert a 'events' hash as described by the original poster to an
Array prob/value pairs

def futon_hash_to_wr(hash)
hash.collect do |value, freq|
[freq, value]
end.extend(WeightedRand).normalize!
end

Regards,

Tom

```