7

I'm just fiddling with a simulation of (Mendel's First Law of Inheritance).

Before i can let the critters mate and analyze the outcome, the population has to be generated, i.e., a list has to be filled with varying numbers of three different types of tuples without unpacking them.

While trying to get familiar with itertools (I'll need combinations later in the mating part), I came up with the following solution:

import itertools

k = 2
m = 3
n = 4

hd = ('A', 'A')       # homozygous dominant
het = ('A', 'a')      # heterozygous 
hr = ('a', 'a')       # homozygous recessive

fhd = itertools.repeat(hd, k)
fhet = itertools.repeat(het, m)
fhr = itertools.repeat(hr, n)

population = [x for x in fhd] + [x for x in fhet] + [x for x in fhr]

which would result in:

[('A', 'A'), ('A', 'A'), ('A', 'a'), ('A', 'a'), ('A', 'a'), ('A', 'a'), ('A', 'a'), ('A', 'a'), ('A', 'a')]

Is there a more reasonable, pythonic or memory saving way to build the final list, e.g. without generating the lists of for the three types of individuals first?

Klaus-Dieter Warzecha
  • 2,265
  • 2
  • 27
  • 33

3 Answers3

6

You could use itertools.chain to combine the iterators:

population = list(itertools.chain(fhd, fhet, fhr))

Though I would say there's no need to use itertools.repeat when you could simply do [hd] * k. Indeed, I would approach this simulation as follows:

pops = (20, 30, 44)
alleles = (('A', 'A'), ('A', 'a'), ('a', 'a'))

population = [a for n, a in zip(pops, alleles) for _ in range(n)]

or perhaps

allele_freqs = ((20, ('A', 'A')),
                (30, ('A', 'a')),
                (44, ('a', 'a')))

population = [a for n, a in allele_freqs for _ in range(n)]
David Robinson
  • 77,383
  • 16
  • 167
  • 187
  • Personally, I feel that using range is not very pythonic, but that's a pretty minor style issue – Slater Victoroff Jun 14 '13 at 18:06
  • @SlaterTyranus: How is `range` not Pythonic? – David Robinson Jun 14 '13 at 18:07
  • like I said, it's a small thing, but seeing range always reminds me of Java and is less functional, but it's really a personal thing. – Slater Victoroff Jun 14 '13 at 18:08
  • @DavidRobinson Amazing! I realize that i only touched the surface of list comprehensions so far. BTW, good that you used the term allel which i avoided in order not to frighten anybody ;) – Klaus-Dieter Warzecha Jun 14 '13 at 18:33
  • @KlausWarzecha: Cool! Now that I think of it allele was actually the wrong term (since these are pairs of alleles), I should have used genotype. But I'm glad it answers your question. – David Robinson Jun 14 '13 at 18:40
  • +1, I just noticed this answer includes a mention of the one I provided. I think it would have been even better to lead with it explicitly since it is a "more reasonable, pythonic or memory saving way to build the final list". – dansalmo Jun 14 '13 at 18:52
1

This should work I suppose.

pops = [2,3,4]
alleles = [('A','A'), ('A', 'a'), ('a','a')]
out = [pop*[allele] for pop, allele in zip(pops,alleles)]
print [item for sublist in out for item in sublist]

I have put the code on CodeBunk so you could run it too.

spicavigo
  • 4,116
  • 22
  • 28
0
population = 2*[('A', 'A')] + 3*[('A', 'a')] + 4*[('a', 'a')]

or

hd = ('A', 'A')       # homozygous dominant
het = ('A', 'a')      # heterozygous 
hr = ('a', 'a')       # homozygous recessive

population = 2*[hd] + 3*[het] + 4*[hr]
dansalmo
  • 11,506
  • 5
  • 58
  • 53