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

Rob Hooft rob at hooft.net
Mon Aug 16 10:06:05 CDT 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"




More information about the Numpy-discussion mailing list