# [Numpy-discussion] Is there a better way to do this?

Rob Hooft rob at hooft.net
Mon Aug 16 10:06:05 EDT 2004

```Hee-Seng Kye wrote:
> My question is not directly related to NumPy, but since many people here
> deal with numbers, I was wondering if I could get some help; it would be
> even better if there is a NumPy (or Numarray) function that takes care
> of what I want!
>
> I'm trying to write a program that computes six-digit numbers, in which
> the left digit is always smaller than its following digit (i.e., it's
> always ascending).  The best I could do was to have many embedded 'for'
> statement:
>
> c = 1
> for p0 in range(0, 7):
>   for p1 in range(1, 12):
>     for p2 in range(2, 12):
>       for p3 in range(3, 12):
>         for p4 in range(4, 12):
>           for p5 in range(5, 12):
>             if p0 < p1 < p2 < p3 < p4 < p5:
>               print repr(c).rjust(3), "\t",
>               print "%X %X %X %X %X %X" % (p0, p1, p2, p3, p4, p5)
>               c += 1
> print "...Done"
>
> This works, except that it's very slow.  I need to get it up to
> nine-digit numbers, in which case it's significantly slow.  I was
> wondering if there is a more efficient way to do this.
>
> I would highly appreciate it if anyone could help.

Sorry for taking a month. My solution is not faster than any of the ones
that have already been proposed, but it is more elegant because it does
not require the "n" nested for loops.

Another hint is to use a generator for this purpose.

Advantage is that the base and the number of digits can both be
externally defined!

Regards,

Rob

# As a reference, the general case where digits are not created in
# order
def gen(ndigits, base):
dig = [0]*ndigits
yield dig
while 1:
for num in range(ndigits-1,-1,-1):
if dig[num] < base - 1:
dig[num] += 1
break
else:
dig[num] = 0
else:
return
yield dig

def genordered(ndigits, base):
if ndigits > base:
return
dig = range(ndigits)
yield dig
while 1:
for num in range(ndigits-1,-1,-1):
if dig[num] < base-ndigits+num:
dig[num] += 1
for num2 in range(num+1,ndigits):
dig[num2] = dig[num2-1] + 1
break
else:
return
yield dig

c = 1
for dig in genordered(ndigits = 6, base = 12):
# This is the same as your print statement, but again independent of
# the number of digits
print "%3d\t"%c,' '.join(map(lambda x: "%X"%x, dig))
c += 1
print "...Done"

```