# Is there a better way of doing this?

Scott David Daniels Scott.Daniels at Acm.Org
Fri Mar 6 23:13:47 CET 2009

```mattia wrote:
> Here is my last shot, where I get rid of all the old intermediate
> functions:
>
> def selection(fitness, population):
>     lp = len(population)
>     roulette_wheel = []
>     for x in population:
>         roulette_wheel += [x]*fitness(x)
>     selected_population = [[]]*lp
>     selected_population[:2] = sorted(population, key=fitness,
> reverse=True)[:2]
>     selected_population[2:] = [choice(roulette_wheel) for _ in range
> (lp-2)]
Try something like this to choose likely couples:

import random
import bisect

def choose_pairs(fitness_population, decider=random):
'''Pick and yield pairs weighted by fitness for crossing.

We assume weighted_population has fitness already calculated.
decide is a parameter to allow testing.
'''
total = 0
cumulative = []
candidates = []
for fitness, individual in set(fitness_population):
# calculate total weights, extract real candidates
if fitness > 0:
total += fitness
cumulative.append(total)
candidates.append(individual)
assert len(candidates) > 1
while True:
# pick a candidate by weight
c0 = decider.random() * total
first = bisect.bisect_left(cumulative, c0)
if first:
weighting = cumulative[first] - cumulative[first - 1]
else:
weighting = cumulative[0]
# pick another distinct candidate by fitness
c1 = choice = decider.random() * (total - weighting)
if choice >= cumulative[first] - weighting:
choice += weight # adjust to avoid selecting first
second = bisect.bisect_left(cumulative, choice)
yield candidates[first], candidates[second]

--Scott David Daniels
Scott.Daniels at Acm.Org

```