views:

89

answers:

3
+2  Q: 

reuse generators

I want to check the central limit with dices. Roll D dices. Sum the results. Repeat the same thing for N times. Change D and repeat.

There's no need to store random values so I want to use only generators. The problem is that the generators are consumed; I can't reuse them many times. Now my code uses explicit for and I don't like it.

dice_numbers = (1, 2, 10, 100, 1000)
repetitions = 10000
for dice_number in dice_numbers: # how many dice to sum
    sum_container = []
    for r in range(repetitions):
        rool_sum = sum((random.randint(1,6) for _ in range(dice_number)))
        sum_container.append(rool_sum)
        plot_histogram(sum_container)

I want to create something like

for r in repetitions:
    rools_generator = (random.randint(1,6) for _ in range(dice_number)
    sum_generator = (sum(rools_generator) for _ in range(r))

but the second time I reuse rools_generator it is consumed. Do I need to construct a generator class?

+3  A: 

You could do it like this:

for r in repetitions:
    make_rools_generator = lambda: (random.randint(1,6) for _ in range(dice_number))
    sum_generator = (sum(make_rools_generator()) for _ in range(r))

This creates a function called make_rools_generator that, when called, creates a new generator that supplied the dice rolls.

Greg Hewgill
Assuming `repetitions` is an int, it will be a wee bit hard to iterate.
msw
True. My improvement to the given code is limited to the function returning a generator. :)
Greg Hewgill
A: 

What about this:

list(list((sum((random.randint(1,6) for _ in range(dn))) for __ in range(10000))) for dn in (1, 2, 10, 100, 1000))
wiso
+2  A: 

I think you may be working too hard, and you are definitely creating unnecessary lists with range(). In the spirit of being a little more explicit than the genexprs above:

import random

def die_roller(throws):
    """generates throws rolls of a die"""
    for _ in xrange(throws):
        yield random.randint(1, 6)

roller = die_roller(10)
print type(roller)      # => <type 'generator'>
print list(roller)      # => [6, 6, 3, 1, 6, 3, 1, 5, 4, 4]
print sum(roller)       # roller was exhausted, generates null list thus 0 sum

big_roller = die_roller(10**5)
print sum(big_roller)   # => 3500238

I think that gets you the rudiments of what you are looking for.

msw
-1: `rools_generator` is a generator. Notice the round rather than square brackets.
Max Shawabkeh
you noticed that 16 seconds before I did, edited. thanks.
msw