random playing soundfiles according to rating.
Ben Cartwright
bencvt at gmail.com
Thu Feb 9 20:07:09 EST 2006
kp87 at lycos.com wrote:
> But i am stuck on how to do a random chooser that works according to my
> idea of choosing according to rating system. It seems to me to be a bit
> different that just choosing a weighted choice like so:
...
> And i am not sure i want to have to go through what will be hundreds of
> sound files and scale their ratings by hand so that they all add up to
> 100%. I just want to have a long list that i can add too whenever i
> want, and assign it a grade/rating according to my whims!
Indeed, manually normalizing all those weights would be a downright
sinful waste of time and effort.
The solution (to any problem, really) starts with how you conceptualize
it. For this problem, consider the interval [0, T), where T is the sum
of all the weights. This interval is made up of adjacent subintervals,
one for each weight. Now pick a random point in [0, T). Determine
which subinterval this point is in, and you're done.
import random
def choose_weighted(zlist):
point = random.uniform(0, sum(weight for key, weight in zlist))
for key, weight in zlist: # which subinterval is point in?
point -= weight
if point < 0:
return key
return None # will only happen if sum of weights <= 0
You'll get bogus results if you use negative weights, but that should
be obvious. Also note that by using random.uniform instead of
random.randrange, floating point weights are handled correctly.
Test it:
>>> data = (('foo', 1), ('bar', 2), ('skipme', 0), ('baz', 10))
>>> counts = dict((key, 0) for key, weight in data)
>>> for i in range(10000):
... counts[choose_weighted(data)] += 1
...
>>> [(key, counts[key]) for key, weight in data]
[('foo', 749), ('bar', 1513), ('skipme', 0), ('baz', 7738)]
>>>
--Ben
More information about the Python-list
mailing list