generating canonical list of tuples?
Jason Orendorff
jason at jorendorff.com
Fri Jan 4 03:56:24 EST 2002
> Ok, so I've tried a function which brute force cranks out the tuples by
> adding one to the last element, carrying it over, etc. And I
> wrote the exec method. And I wrote the recursion method. The exec
> runs at least six times faster than the brute force method.
I haven't been following this thread; perhaps someone already
suggested using a generator for this.
# Python 2.2 only
from __future__ import generators
def genWhiteTuples(total, blocks):
""" The 'brute force' method, as a generator. """
if total < blocks:
# Trivial case
return
result = [1] * blocks
running_total = blocks
while 1:
yield tuple(result)
while running_total < total:
# Easy. Just increment the rightmost number.
result[-1] += 1
running_total += 1
yield tuple(result)
# Look for an element to reset.
index = blocks - 1
while index > 0:
if result[index] > 1:
# We found an element to reset.
# (Must also increment the element to its left.)
running_total = running_total - result[index] + 2
result[index] = 1
result[index-1] += 1
break
index -= 1
else:
# This means we're done.
return
You can use a generator in a for statement,
just as you would use a list.
for x1, x2, x3 in genWhiteTuples(10, 3):
do_something(x1, x2, x3)
In this case, RAM consumption is low, because the tuples are
generated one at a time, as needed, instead of generating them
all at once and putting them in a list. In fact, I can even:
n = 0
for t in genWhiteTuples(39, 6):
n += 1 # count how many results
print n
It runs in about 10 seconds on my machine, and doesn't use much RAM.
The result is 3262623.
If you *must* have a list, the syntax is pretty simple:
L = list(genWhiteTuples(20, 10))
On my machine, this runs about as fast as your exec-based version,
and uses about the same amount of memory.
## Jason Orendorff http://www.jorendorff.com/
More information about the Python-list
mailing list