algorithm - What's the pythonic way to run a lottery? -


i need pick several random items weighted set. items higher weight more picked. decided model after lottery. feel solution makes c++, don't think makes python.

what's pythonic way of doing this?

def _lottery_winners_by_participants_and_ticket_counts(participants_and_ticket_counts, number_of_winners):     """     returns list of winning participants in lottery. in lottery,     participant can have multiple tickets, , participants can win     once.     participants_and_ticket_counts list of (participant, ticket_count)     number_of_winners maximum number of lottery winners     """      if len(participants_and_ticket_counts) <= number_of_winners:         return [p (p, _) in participants_and_ticket_counts]      winners = []      _ in range(number_of_winners):         total_tickets = sum(tc (_, tc) in participants_and_ticket_counts)         winner = random.randrange(0, total_tickets)          ticket_count_offset = 0         participant_ticket_count in participants_and_ticket_counts:             (participant, ticket_count) = participant_ticket_count              if winner < ticket_count + ticket_count_offset:                 winners.append(participant)                 participants_and_ticket_counts.remove(participant_ticket_count)                 break              ticket_count_offset += ticket_count      return winners 

edit: sorry forgot earlier, weight integer in thousands.


edit: think have final solution based on comment of @flo

notes

  • i'm working in python 2.7, created own accumulate(). works differently (and think better) accumulate() in python 3. version can accumulate iterable of tuples based on add function.

  • i have special knowledge participants_and_ticket_counts mutable list , not used after _lottery_winners_by_participants_and_ticket_counts() called. that's why can pop() it.

here's solution:

def _lottery_winners_by_participants_and_ticket_counts(participants_and_ticket_counts, number_of_winners):     """     returns list of winning participants in lottery. in lottery,     participant can have multiple tickets, , participants can win once.     participants_and_ticket_counts list of (participant, ticket_count)     number_of_winners maximum number of lottery winners     """     def _accumulate(iterable, func):         total = 0         element in iterable:             total = func(total, element)             yield total      if len(participants_and_ticket_counts) <= number_of_winners:         return list(winner (winner, _) in participants_and_ticket_counts)      winners = list()     _ in range(number_of_winners):         accumulation = list(_accumulate(participants_and_ticket_counts, lambda total, ptc: total + ptc[1]))         winning_number = random.randrange(0, accumulation[-1])         index_of_winner = bisect.bisect(accumulation, winning_number)         (winner, _) = participants_and_ticket_counts.pop(index_of_winner)         winners.append(winner)     return winners 

thanks help!

numpy.random.choice has nice solution this. here's how can use it:

>>> import numpy np >>> numpy.random import choice >>> names = ['harry', 'sally', 'joe', 'bob', 'angela', 'jack', 'jill', 'jeff'] >>> weights = [1,4,6,3,5,7,10,14] >>> p = np.array(weights, dtype=float) / sum(weights) >>> p array([ 0.02,  0.08,  0.12,  0.06,  0.1 ,  0.14,  0.2 ,  0.28])  >>> choice(names, size=5, p=p) array(['jill', 'jack', 'jeff', 'jeff', 'angela'],        dtype='|s6') >>> choice(names, size=5, p=p) array(['jill', 'jack', 'joe', 'jill', 'sally'],        dtype='|s6') >>> choice(names, size=5, p=p) array(['jack', 'angela', 'joe', 'sally', 'jill'],        dtype='|s6') 

however, function added in numpy 1.7. if have older version, can copy function: http://pastebin.com/f5gti0qj


Comments

Popular posts from this blog

jquery - Invalid Assignment Left-Hand Side -

java - Play! framework 2.0: How to display multiple image? -

gmail - Is there any documentation for read-only access to the Google Contacts API? -