1

From the PacktPub's book "Python Data Structures and Algorithms" (authored by Benjamin Baka) section on Backtracking from chapter 3, they have this function (page 81):

def bitStr(n, s):
    if n == 1: return s
     return [digit + bits for digit in bitStr(1, s) 
             for bits in bitStr(n - 1, s)]

 print(bitStr(3,'abc'))

Returns:

['aaa', 'aab', 'aac', 'aba', 'abb', 'abc', 'aca', 'acb', 'acc', 'baa', 'bab', 'bac', 'bba', 'bbb', 'bbc', 'bca', 'bcb', 'bcc', 'caa', 'cab', 'cac', 'cba', 'cbb', 'cbc', 'cca', 'ccb', 'ccc']

The book's explanation:

Notice the double list compression and the two recursive calls within this comprehension. This recursively concatenates each element of the initial sequence, returned when n = 1, with each element of the string generated in the previous recursive call. In this sense it is backtracking to uncover previously ingenerated combinations. The final string that is returned is all n letter combinations of the initial string.

Well, besides how unpythonic it feels by them using a list comprehension for something like this (or maybe it's just me), I simply can't understand it.

I rewrote the whole thing and added my comments to the code with what I understood so far and where I'm stuck.

def test(n, s):
     # this one's obvious
     if n == 1: return s

     result = list() # so's this

     """
     From what I can tell, the first recursive call in the outer
     loop forces the function's conditional statement to 
     activate. So, with the example of `abc` as the second
     input to the function, the outer for loop just loops
     over that string, `abc` in this case.
     """
     for digit in test(1, s):
         """
         This is where I start to lose my grip on what's happening.
         So, going to the above returned list as given by the book,
         I can see where the first item, i.e `aaa`, in the list
         comes from.

         So, here's what I see when it comes to that first item. 
         `digit` now storing the first 'a' that later get's added,
         the second recursive call in this second loop (if w-
         e're going with the original example call from the 
         book: `test(3, 'abc')`) sets the first input to 2 on
         the first iteration.

         I'm guessing this makes it so it avoids the conditional 
         statement. With that avoided, we still have the string
         'abc'. 

         The first iteration of the loop takes the first 
         letter, 'a', and adds it to `digit`. 

         I'm a bit confused on how then the loop goes back through 
         the function to get the third 'a' to complete the 
         final list's first item, 'aaa'.

         Though, say I did understand that at the time of posting
         this question, what I'm totally confused about it is
         how this supposedly 'Backtracks', and gets the
         final list's second item, 'aab', and all subsequent items.
         """
         for bits in test(n-1, s):
             result.append(digit + bits)

     return result

Any help explaining this all would be appreciated. Plus, it would be great if someone can confirm correct what I "claim" to understand already in my code comments.

J Doe
  • 129
  • 1
  • 9
  • 1
    This code seems pointlessly overcomplicated. Why loop over `for digit in bitStr(1, s)` when, as the book directly explains, this is always going to be `s`? It’s also pretty misleading to refer to the list of generated strings as “the final string”. Maybe this just isn’t a very good book, and that’s why you’re struggling to follow it? (Or maybe it’s a good book in general, but the author was having an off day when writing this example and its explanation?) – abarnert Aug 04 '18 at 01:44
  • Anyway, when trying to understand a recursive algorithm, it usually helps to pick a small example (which you’ve done with `'abc'` and `3`) and either trace it through by hand, drawing a tree of all of the recursive calls, or run it in a debugger or (if the example is small enough, which this one is) a visualizer like Python Tutor. Being able to literally picture the control flow (and see what values get passed down and up the tree) usually makes it a lot easier to get a grasp of why it works. – abarnert Aug 04 '18 at 01:49
  • @abarnert Yeah, I don't really know much about the author or the book. PacktPub had it available to claim the other day as a "free offer", so I got it and started skimming through it. I edited the question to add who the author is. As for your recommendations, thank you. I'll definitely do those. I didn't even know about Python Tutor, so I'll definitely check that out. – J Doe Aug 04 '18 at 02:08

0 Answers0