[Tutor] variable numbers of for loops (also iteration/recursion)

Chris Fuller cfuller084 at thinkingplanet.net
Tue Nov 23 18:49:42 CET 2010


You can always substitute Iteration for Recursion by making the stack an 
explicit part of your code. As an example, imagine you are traversing this 
directory tree:

birds
birds/owls
birds/owls/snowy
birds/owls/barn
birds/owls/great-horned
birds/eagles
birds/eagles/golden
birds/eagles/bald
birds/eagles/osprey

Where the third-level items are files, rather than more directories.

In a recursive approach, a function is defined that does the recursion. This is 
a feature of recursion. You can't slip it inline with your code (unless your 
language supports inline functions and the right sort of scoping rules, but 
you probably don't want to try that here). The function takes a directory, 
iterates through the contents, calling itself again for every subdirectory.

Your application code calls the function with the argument of "birds". The 
function then calls itself twice, once with "owls" and again with "eagles". 
The contents of these are files, and not directories, so recursion ends.

In an iterative approach, there is a stack and a loop. The loop stops when the 
stack is empty. The loop pops the most recently pushed item from the stack, 
and then pushes onto the stack any subdirectories.

We start with the directory "birds" on the stack. The loop pops "birds" and 
then pushes "owls" and "eagles". It loops twice more to process these, and 
then stops.


Your program is really more iterative than recursive. I couldn't manage a 
recursive expression of the problem. You can always make a iterative version 
of a recursive algorithm, but not necessarily the other way. This makes sense 
when you inspect the problem. Your solution is abstractly equivalent to an n-
dimensional "cube" with side length equal to the length of the alphabet, not 
anything that looks like a tree. One thing I noticed about your generated code 
is that it can be collapsed into a list comprehension:

>>> allwrds('ab',2)
listOfWords=[]
for l0 in alphabet:
    for l1 in alphabet:
        word = "".join([eval("l"+str(i)) for i in range(n)])
        listOfWords.append(word)

['aa', 'ab', 'ba', 'bb']

is equivalent to

>>> alphabet='ab'
>>> [l0+l1 for l0 in alphabet for l1 in alphabet]
['aa', 'ab', 'ba', 'bb']

Now, the result is a 1D list of length len(alphabet)**n. Why not iterate over 
that space, and fill in the blanks? Think of your problem modeled as a n-
dimensional hypercube. The value at any element is equal to the concatenation 
of the n indices of that element's location. Some 2D examples:

allwrds('ab',2):
   a   b
a aa  ab
b ba  bb

allwrds('abc',2):
   a   b   c
a aa  ab  ac
b ba  bb  bc
c ca  cb  cc

Mapping from n dimensions to 1D isn't hard if you know the size of each 
dimension. In this case, they're all equal. I'll use a 3D example to make it 
more clear:

i = 0

  j=0  1  2
k
0   0  1  2
1   3  4  5
2   6  7  8

i = 1

  j=0  1  2
k
0   9 10 11
1  12 13 14
2  15 16 17

i = 2

  j=0  1  2
k
0  18 19 20
1  21 22 23
2  24 25 26

Find the i,j,k for 1D index 17.
Start with the highest order index (i). Divide by the product of the sizes of 
the lower dimensions, which is the length of the alphabet squared. This 
alphabet is length 3, so we divide by 9. We get 1 rmdr 8. i=1. Now take the 
remainder and repeat. 8 divided by 3 is 2 rmdr 2. j=2. You could take it 
another step if using n-cubes and powers of the dimension size, since 3**0 
equals one, and the next answer is still 2, but this fails when the dimensions 
aren't all equal. k=2. Got that?

Now these i,j,k values are just indices into the alphabet! Just get the letter 
at that indexd and join them up. Here's the code:

def allwrds(alphabet, n):
   listOfWords=[]
   for i in range(len(alphabet)**n):
      word = ''
      q = i
      for j in range(n-1):
         q, r = divmod(q, len(alphabet))
         word += alphabet[q]
         q = r
      word += alphabet[q]
      listOfWords.append(word)
   return listOfWords


Cheers


More information about the Tutor mailing list