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