I have a list of candidates which looks like this:
candidates = [
{
'name': 'John',
'rank': 13
},
{
'name': 'Joe',
'rank': 8
},
{
'name': 'Averell',
'rank': 5
},
{
'name': 'William',
'rank': 2
}
]
What I want to do is semi-randomly pick one of these candidates, based on its squared rank. So that a candidate A
having a rank twice as big as B
, will have 4 times more chances to be picked than B
.
Here is a naive implementation of the idea I had to solve this problem:
def pick_candidate(candidates):
# initiates a global probability space
prob_space = []
# bring the max rank to 20
# to avoid useless CPU burning
# while keeping a good granularity -
# basically, just bring the top rank to 20
# and the rest will be divided proportionally
rate = candidates[0]['rank'] / 20
# fills the probability space with the indexes
# of 'candidates', so that prob_space looks like:
# [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1]
# if candidates[0] has rank 3 and candidates[1] has rank 2
for i, c in enumerate(candidates):
rank = c['rank'] / rate
for j in range(int(rank*rank)):
prob_space.append(i)
# picks a random index from the probability space
picked_prob_space_index = random.randint(0, len(prob_space)-1)
# retrieves the matching candidate
picked_candidate_index = prob_space[picked_prob_space_index]
return candidates[picked_candidate_index]
The questions I'm thinking of, concerning the above code, are:
- Concept: Is the core principle of the algorithm (the idea of building
prob_space
, etc) overkill and solvable more easily in other ways or with builtins - Implementation: This core principle put aside, what do you think of the implementation? Would you think of a better, cleaner way to write it?