Actually you should break the function down first:

A loop has a few parts:

  1. the header, and processing before the loop. May declare some new variables

  2. the condition, when to stop the loop.

  3. the actual loop body. It changes some of the header's variables and/or the parameters passed in.

  4. the tail; what happens after the loop and return result.

Or to write it out:

foo_iterative(params){
    header
    while(condition){
        loop_body
    }
    return tail
}

Using these blocks to make a recursive call is pretty straightforward:

foo_recursive(params){
    header
    return foo_recursion(params, header_vars)
}

foo_recursion(params, header_vars){
    if(!condition){
        return tail
    }

    loop_body
    return foo_recursion(params, modified_header_vars)
}

Et voilà; a tail recursive version of any loop. breaks and continues in the loop body will still have to be replaced with return tail and return foo_recursion(params, modified_header_vars) as needed but that is simple enough.


Going the other way is more complicated; in part because there can be multiple recursive calls. This means that each time we pop a stack frame there can be multiple places where we need to continue. Also there may be variables that we need to save across the recursive call and the original parameters of the call.

We can use a switch to work around that:

bar_recurse(params){
    if(baseCase){
        finalize
        return
    }
    body1
    bar_recurse(mod_params)
    body2
    bar_recurse(mod_params)
    body3
}


bar_iterative(params){
    stack.push({init, params})

    while(!stack.empty){
        stackFrame = stack.pop()

        switch(stackFrame.resumPoint){
        case init:
            if(baseCase){
                finalize
                break;
            }
            body1
            stack.push({resum1, params, variables})
            stack.push({init, modified_params})
            break;
        case resum1:
            body2
            stack.push({resum2, params, variables})
            stack.push({init, modified_params})
            break;
        case resum2:
            body3
            break;
        }
    }
}
Answer from ratchet freak on Stack Exchange
Top answer
1 of 2
49

Actually you should break the function down first:

A loop has a few parts:

  1. the header, and processing before the loop. May declare some new variables

  2. the condition, when to stop the loop.

  3. the actual loop body. It changes some of the header's variables and/or the parameters passed in.

  4. the tail; what happens after the loop and return result.

Or to write it out:

foo_iterative(params){
    header
    while(condition){
        loop_body
    }
    return tail
}

Using these blocks to make a recursive call is pretty straightforward:

foo_recursive(params){
    header
    return foo_recursion(params, header_vars)
}

foo_recursion(params, header_vars){
    if(!condition){
        return tail
    }

    loop_body
    return foo_recursion(params, modified_header_vars)
}

Et voilà; a tail recursive version of any loop. breaks and continues in the loop body will still have to be replaced with return tail and return foo_recursion(params, modified_header_vars) as needed but that is simple enough.


Going the other way is more complicated; in part because there can be multiple recursive calls. This means that each time we pop a stack frame there can be multiple places where we need to continue. Also there may be variables that we need to save across the recursive call and the original parameters of the call.

We can use a switch to work around that:

bar_recurse(params){
    if(baseCase){
        finalize
        return
    }
    body1
    bar_recurse(mod_params)
    body2
    bar_recurse(mod_params)
    body3
}


bar_iterative(params){
    stack.push({init, params})

    while(!stack.empty){
        stackFrame = stack.pop()

        switch(stackFrame.resumPoint){
        case init:
            if(baseCase){
                finalize
                break;
            }
            body1
            stack.push({resum1, params, variables})
            stack.push({init, modified_params})
            break;
        case resum1:
            body2
            stack.push({resum2, params, variables})
            stack.push({init, modified_params})
            break;
        case resum2:
            body3
            break;
        }
    }
}
2 of 2
2

Following up on @ratchet freak's answer, I created this example of how the Fibonacci function can be rewritten to a while loop in Java. Note that There's a much simpler (and efficient) way to rewrite the Fibonacci with a while loop though.

class CallContext { //this class is similar to the stack frame

    Object[] args;

    List<Object> vars = new LinkedList<>();

    int resumePoint = 0;

    public CallContext(Object[] args) {
        this.args = args;
    }

}


static int fibonacci(int fibNumber) {
    Deque<CallContext> callStack = new LinkedList<>();
    callStack.add(new CallContext(new Object[]{fibNumber}));
    Object lastReturn = null; //value of last object returned (when stack frame was dropped)
    while (!callStack.isEmpty()) {
        CallContext callContext = callStack.peekLast();
        Object[] args = callContext.args;
        //actual logic starts here
        int arg = (int) args[0];
        if (arg == 0 || arg == 1) {
            lastReturn = arg;
            callStack.removeLast();
        } else {
            switch (callContext.resumePoint) {
                case 0: //calculate fib(n-1)
                    callStack.add(new CallContext(new Object[]{arg - 1}));
                    callContext.resumePoint++;
                    break;
                case 1: //calculate fib(n-2)
                    callContext.vars.add(lastReturn); //fib1
                    callStack.add(new CallContext(new Object[]{arg - 2}));
                    callContext.resumePoint++;
                    break;
                case 2: // fib(n-1) + fib(n-2)
                    callContext.vars.add(lastReturn); //fib2
                    lastReturn = (int) callContext.vars.get(0) + (int) callContext.vars.get(1);
                    callStack.removeLast();
                    break;
            }
        }
    }
    return (int) lastReturn;
}
Discussions

python - How to use recursion for "for" loops - Stack Overflow
My code is meant to find the longest path in a matrix, where each value is greater than the one previous. However, I've been instructed to not use for loops at all, which is difficult because I hav... More on stackoverflow.com
🌐 stackoverflow.com
loops - Recursive looping function in Python - Stack Overflow
I have a database that models a foldering relationship to n levels of nesting. For any given folder, I want to generate a list of all child folders. Assuming I have a function called getChildFo... More on stackoverflow.com
🌐 stackoverflow.com
Converting a for loop to recursion in Python - Stack Overflow
Recursive functions usually have two parts. Base case: Handled directly. Corresponds to the body of the innermost loop in your code. More on stackoverflow.com
🌐 stackoverflow.com
October 29, 2016
python - Recursive for loop - Stack Overflow
Communities for your favorite technologies. Explore all Collectives · Ask questions, find answers and collaborate at work with Stack Overflow for Teams More on stackoverflow.com
🌐 stackoverflow.com
Top answer
1 of 2
1

Recursion is about a base case and an iterative case. In your situation, think of the smallest matrix you can - an empty matrix. That is your base case. Your function should return a path length of 0 if it is empty.

The iterative case is a bit more difficult, and usually where things become confusing. The key goal of the iterative case is to reduce the size of the problem, usually by the smallest amount possible.

To overly simplify, if you start with a function like this:

def f(ls):
    for x in ls:
        result = g(x, result)
    return result

Then the iterative version looks like this:

def f(ls, result):
    if 0 == len(x):  # Base Case
        return result
    else:  # Iterative Case
        result = g(x, result)
        return f(ls[1:], result)

The trick is figuring out what of your internal logic goes into g() and how to represent the result.

Let's take a simpler version of your problem, where we deal with a single array and want to return the longest 'path' in that array. A path is a sequence of integers that are incrementing by one.

So, if we have [0,1,2,3] the expected value is 4. If we have [0,1,1,2,3] the expected value is 3. Similarly, 3 would be expected for the input [0,1,2,2,1]. [3,2,1] should return 0.

The most basic signature we require is this:

def f(ls: list[int]) -> int

Essentially, 'a function that takes a list of ints and returns the length of the longest path'. But we have to remember a bit of extra state to do this properly. Specifically, we need to remember the length of the current path we are on, and the lengths of all paths we have found.

def f(ls: list[int], current_path: int) -> int

Let's examine the base case. A base case is any case where reducing the size of your input (in our case 'input' really refers only to ls) would not yield an easier problem to solve. There are two base cases - if the input list is length 0 or 1. In both these cases, we have no need to shrink the problem any further.

def f(ls: list[int], current_path: int) -> int:
    # If there are no elements, current_path is the only valid length
    if 0 == len(ls):
         return current_path
    # If there is one element, increment current_path before returning it, to account for the length that element adds
    if 1 == len(ls):
         return current_path + 1
        

These serve to terminate the recursion. Now lets look at the iterative case:

def f(ls: list[int], current_path: int) -> int:
    # Base cases
    if 0 == len(ls):
        return current_path
    if 1 == len(ls):
        return current_path + 1
    # Iterative case - guaranteed that len(ls) >= 2
    current_path = current_path + 1  # Increment the current_path to account for the current element.
    if ls[1] == ls[0] + 1:
        # In this branch we know that the path will continue.
        return f(ls[1:], current_path)  # ls[1:] reduces our problem space by one element
    else:
        # In this branch the path ends, because the next element breaks the incremental sequence.
        recursive_result = returnf(ls[1:], 0)  # Reduce the problem space and start a new path of length 0
        return max(recursive_result, current_path)  # Choose which path is longer

There is a lot going on here, so I'll break it down in parts. The key thing to remember is that we are going to reduce the problem space - shorten the list - and then recurse with that smaller problem space. The element we are removing is therefore key to determining how we proceed.

Since we are removing one element, we add one to the current path. If the incoming path length was 0, we now have a path length of 1. If it was 3, we now have a path of 4.

Then we check the value of the next element. Is it exactly larger than the current element? If so, we know the path will continue, so we recurse, passing along a list without the current element and the length of our current path.

If it is not exactly one more, we know our current path ends here. In the recursion we pass along a new path length of 0, resetting the counter. But we have to do something with the returned value - decide whether it is larger than the current path as it stands at this element. Hence using max() to choose between the two possibilities.

This gives you a recursive function that iteratively shortens the problem at each step until it finds a base case, at which point it returns - but it returns up through the recursive function, accumulating the results.

(n.b. There are ways to optimize this, clean it up, add default values, etc. I'm skipping that because it doesn't help you think about the recursion.)

Your actual problem is harder. You're going along a two dimensional array. The key insight to have is this: in the iterative step in the example I gave, I looked at all the possible cases for moving forward and chose between them. However, you can go down all possible paths. If you are at a particular element in a two dimensional array, you know that you can go one way or the other - that's two recursive function calls. Because recursion is shortening your problem space, your iterative step can simply trust it will return, and only deal with the results. In your case, that is choosing which of the two recursive calls you made returned the larger result.

(At this point I have to make assumptions about your problem because you included neither a complete specification nor full code.)

def f(matrix: list[list[int], coords: (int, int), current_path: int) -> int:
    # Find all possible 'next steps'. For a next step to be valid it must be exactly one greater than the current location.
    # Base Case - There are no possible next steps -> return current path + 1
    # Increment path
    # Iterative cases
        # There is only one next step -> recurse passing new coordinates and path length
        # There are two or three next steps -> recurse passing new coordinates and path length, then choose which result is the longest.

The difficulty here is that this finds the longest path from any given starting position. To truly find the longest path in the matrix, you would have to add a fourth argument to your function - a list of all the starting positions you have tried. Then you would change your logic for finding the next steps from 'is it strictly one larger' to 'is it strictly one larger or have I not tried starting from that point'?

# Use type aliases so you're clear about the types
type Matrix: list[list[int]]
type Coordinate: (int, int)  # x-y coordinates
type Cache: list[Coordinate]  # All the places we've started from

def f(matrix: Matrix, 
      coords: Coordinate, 
      current_path: int, 
      starting_points: Cache) -> int:
    if 0 == len(matrix):
      return current_path
    if 1 == len(matrix) and 0 == len(matrix[0]):
      return current_path
    current_path = current_path + 1  # From here on, we have a valid element at this coordinate
    if 1 == len(matrix) and 1 == len(matrix[0]):
      return current_Path
    moves = get_all_moves(...)
    if 0 == len(moves):  # This is *also* a base case - the problem cannot be shrunk any further!
      return current_path
    results = try_each_move(moves)  # This is also a recursive function... but a *different* recursive function, in order to avoid using a for loop (or list comprehension)
    return max(max(results), current_path)

A few closing notes:

  • Do try to adhere to python style guides. It makes reading python easier!
  • Any information you think you need to store outside the function can just be passed as a parameter. Pure recursive functions don't have access to a closure or outer scope. Depending on your case, this may not be the most efficient solution, but it is where you should start until you're much more comfortable with recursion.
  • Similarly, if copying a value rather than a reference makes it easier for your to reason about what you're doing, do that first. Efficiency is for later. Clarity first.
  • Recursion often (though not always) easier if you're building up a solution from the return of the recursion call. In the examples here, the max() function is doing that accretion, but you could imagine inverting the approach here and first doing the recursive call, which returns two values - the value of the last element and the length of the path. Then you could decide if you're smaller than that value. I didn't do that here because you'd have to remember two path lengths at a time.
  • In this specific problem, do take care with the cache. You can't just remember if you've ever visited a coordinate.
2 of 2
-1

Recursion is just a function that keeps calling itself until it reaches a condition that disallows it from continuing.

Here's an example that's themed toward your needs.

""" Emulation Of:
for row in range (len(matrix)):
    for col in range (len(matrix[0])):
        print(matrix[row][col])
"""

matrix = [[1,2,3],[4,5,6],[7,8,9]]

#wrapping everything in this function makes `i` unreachable
#because it should be managed internally
def process_matrix(r:int, c:int) -> None:
    
    def columns(i:int=0, r:int=0) -> None:
        if i==c: return     #columns finished
        print(matrix[r][i]) #work
        columns(i+1, r)     #next column

    def rows(i:int=0) -> None:
        if i==r: return     #rows finished
        columns(0, i)       #recurse all columns for this row
        rows(i+1)           #next row
        
    rows(0)                 #start recursion

#use    
process_matrix(len(matrix), len(matrix[0]))

If you are trying to retrieve data, you have to return the "recursion call". Otherwise, you'll get None back from the very first call, and the recursion will carry on in a way that is unreachable by your code.

data = [10,20,30,40,50,60]   

def where_is_50(i:int=0) -> int:
    if data[i] == 50:
        return i            #stop recursion
    return where_is_50(i+1) #next
 
print(where_is_50())

If it isn't clear, The first time the function is called, it is not 50 so, it returns a call to itself. However, the actual return can't finish until the call does. Essentially, you end up with a string of "active" functions that are all waiting for the call that finds 50. When 50 is found, the return value keeps ascending through all the calls back to the very first one.

Whatever recursive functions you make should have a local reference to the data to traverse. In other words, don't pass your entire matrix on each call. Pass names or indexes recursively.

🌐
Quora
quora.com › How-do-you-convert-iterative-code-to-recursive
How to convert iterative code to recursive - Quora
Answer (1 of 5): Here the iterative code to find the factorial of a given number. [code]n=5 res=1 for i in range(n,0,-1): res*=i print(res) [/code]Output: 120 To convert the iterative code to recursive code , first you need to find the terminating condition which end the function call and the...
Find elsewhere
Top answer
1 of 2
1

I think the key here is really in just getting used to thinking about recursion and how to solve problems with it. It really is a "work backwards" kind of a solution. With that in mind, let's see if we can develop a recursive solution together.

  1. Whenever you're writing something recursive, you're essentially always going to want to start at the end of the problem -- what will or should the behavior of the code be when it is finished, when it has found the answer? What overall environment and inputs should we expect at that final state? And, most importantly, how can we "propagate" our answer back up the call stack without losing anything we care about in the process?
    • First things first: before we can properly get started thinking about or writing any code, we need to make sure we're equipped with the right tools for the job: choosing and preparing the proper data structures (where minor differences in choice can be the difference between hacking away at an incorrect or suboptimal solution for days, or figuring out an elegant and optimal one in a few hours!) The dictionary you've provided as shown here really isn't doing you any favors: the values, as lists of lists, are difficult to check through cleanly and efficiently, Pythonically without a lot of cruft. Personally, I think this particular problem lends itself well to a dict of dicts, i.e.

      d = {
           'dict1': {
               'Movie1': 'Fiction',
               'Movie2': 'Romance'
            },
            etc...
          }
      

      considering that the dict values already form a natural association (in fact, they closely resemble a popular way of instantiating dicts: with a list of (key, value) tuples). If this doesn't seem like your cup of tea, I think another strategic choice would be having parallel dicts of lists -- sharing the same keys, but having one just for movie titles and one just for genres. The lists should be easy to use while coding your solution, but (unlike the nested dictionaries before -- dict_values and dict_keys are implemented as sets behind the scenes) won't make lookup quite as quick...so depending on your use case this would be less preferable. A quick illustrative example:

      movies = {'dict1': ['Movie1', 'Movie2'], 'dict2': ['Movie3']}
      genres = {'dict1': ['Fiction', 'Romance']}
      

      In this set-up, you'd first check through the level of dictionary keys and then the list indices of the value for the matching entry in the corresponding dictionary.

      In general, though, it can really simplify your code and your thought process to not try to cram too many different things (data with different meanings or uses) into the same object rather than having a neat, well-laid plan for utilizing a collection of objects designed to work together, especially if that can be done in a manner so as to not waste a lot of memory.

  • Now that we have a general plan (the dict-of-dicts approach first described above) we can return to our original question: where do we end when solving this problem? What is our base case (important terminology as you progress with recursion)? Well, that actually seems trivially easy -- the base case is when we are looking at some collection (a list, set, dict keys or values, what have you) and we find that it contains the movie title we are searching for. So we can already write our base case (partially)

    def recursive_movie_search(movie, db, ...):
        if movie in db:
            return movie, db[movie]
        # Rest of search logic goes here
    

    Notice that because of our choice of data structure, once we've found the movie title we've already got the genre as well, since they're formally associated. We're not quite done yet though, as hinted at by the comment and the ellipsis in the function signature above.

  • Here's the last challenge to the recursive technique -- how do we make it so that, by the time we find what we're looking for, we have any and all other information we need to produce our final answer? Often, as in this case, this has to do with cleverly passing along any necessary auxiliary information on our way (down the recursive call stack) to solving the problem. One simple way (not that there's only one!) to finish off the implementation in this case would be something like the following:

    def recursive_movie_search(movie, db, prev=None):
        prev = prev or []
    
        if movie in db:
            return prev.extend((movie, db[movie]]))
        for key in db:
            search = recursive_movie_search(movie, db[key], prev + [key])
            if search: return search
    
        return False
    

Now, to be fair, the problem as you gave it wasn't particularly well-suited to a recursive solution since the searching we needed to do was quite shallow. But the approach above should work with arbitrarily deeply nested dictionaries (then once you get the answer you can decide which of the keys along the path that led to it are significant and worth reporting, or should just be omitted). The only assumption made is that at the bottom level the movie titles will be associated with their genres.

Note also that there are several minor changes you could have made just based on personal choice: instead of accumulating the keys and passing them into the function, this could have been handled simply in the recursive call, e.g. search = key + recursive_movie_search(movie, db[key]) but then this would have required a slightly more thorough check on the next line to ensure that we got a "hit" with that call. Also, you could just as easily return None, an empty list [], or any other item whose boolean value evaluates to False (in the failure case where the movie isn't found) and this logic will work just as well. You just need some kind of flag there to tell you that the search failed -- you could even use a special string that you check for specifically.

P.S. This is my first answer on StackOverflow -- I really hope it helps! And I'm very much open to further questions or feedback on how I can improve :)

2 of 2
0

Assuming that your given structure does not change for other cases, I think this is what you are looking for:

dic = {
    "dict1": [["Movie1", "Fiction"], ["Movie2", "Romance"]],
    "dict2": [["Movie3", "Comedy"]],
}

def rec_search(data, movie_name):
    if isinstance(data, dict):
        for key in data.keys():
            result = rec_search(data[key], movie_name)
            if isinstance(result, tuple):
                return f"found in {key}; Title: {result[0]}; Genre: {result[1]}"
        return None
    elif isinstance(data, list):
        for element in data:
            if isinstance(element, str):
                if element == movie_name:
                    return element
            else:
                result = rec_search(element, movie_name)
                if result:
                    return (result, element[1])
        return None


print(rec_search(dic, "Movie2"))
🌐
Reddit
reddit.com › r/learnprogramming › [python] converting nested for-loop into recursion
r/learnprogramming on Reddit: [Python] Converting Nested For-Loop into Recursion
February 17, 2020 -

Hey guys, I'm pretty new to python and I'd like to practice using Recursion in my code to further assist my understandings with the recursive function. From what I am aware of, identifying a base case is required to prevent infinite recursion but I cannot seem to figure out the base case for this scenario.

Simplified code as shown below:

for y in range(N):         
    for x in range(M):             
        if origin[x][y] == 1 and CellsMap[x][y] == 0:                        
           CellsCounter += 1             
        DiscoverCells(origin, x, y, CellsCounter)  

Basically the above code will scan for every (x, y) coordinate in a grid (Implemented by the nested For Loop)

How do I go about converting this code into recursion, with a call to function of def DiscoverCells()?

Thanks in advance!!

Top answer
1 of 3
3
First, let's eliminate for loops because we want to avoid thinking about what a for loop in Python translates to. y = 0 while y < N: x = 0 while x < M: if origin[x][y] == 1 and CellsMap[x][y] == 0: CellsCounter += 1 DiscoverCells(origin, x, y, CellsCounter) x = x + 1 y = y + 1 What state do we have N, y, M, x, origin and CellsCounter. so let's start with making a function taking these inputs as arguments. def f(y, N, x, M, origin, CellsCounter): pass This looks too complicated to do all at once so lets start with the inner loop while x < M: if origin[x][y] == 1 and CellsMap[x][y] == 0: CellsCounter += 1 DiscoverCells(origin, x, y, CellsCounter) x = x + 1 will be converted to def inner(y, N, x, M, origin, CellsCounter): pass First, let's copy paste the body of the loop into inner def inner(y, N, x, M, origin, CellsCounter): if origin[x][y] == 1 and CellsMap[x][y] == 0: CellsCounter += 1 DiscoverCells(origin, x, y, CellsCounter) x = x + 1 Now, at the end we need to do the following logic if while condition is true: loop again else: return result So, let's just put that logic in def inner(y, N, x, M, origin, CellsCounter): if x < M: if origin[x][y] == 1 and CellsMap[x][y] == 0: CellsCounter += 1 DiscoverCells(origin, x, y, CellsCounter) return inner(y, N, x + 1, M, origin, CellsCounter) else: return (y, N, x, M, origin, CellsCounter) Notice that we return all things that can change during any execution of our loop. We'll eliminate the unchanging stuff later. Now, we do a similar thing for the outer loop y = 0 while y < N: x = 0 INNER LOOP y = y + 1 Converting to a function outer def outer(y, N, x, M, origin, CellsCounter): x = 0 INNER LOOP y = y + 1 Adding the looping logic back in def outer(y, N, x, M, origin, CellsCounter): if y < N: x = 0 INNER LOOP return outer(y + 1, N, x, M, origin, CellsCounter) else: return (y, N, x, M, origin, CellsCounter) How does inner loop work? We call the inner loop function and then update all 6 of our variables to what they are after performing the inner loop. def outer(y, N, x, M, origin, CellsCounter): if y < N: x = 0 (y, N, x, M, origin, CellsCounter) = inner(y, N, x, M, origin, CellsCounter) return outer(y + 1, N, x, M, origin, CellsCounter) else: return (y, N, x, M, origin, CellsCounter) Now let's pretty some stuff up. First, notice that the value x is never changed between calls to outer so let's eliminate that variable from outer It also won't get us def outer(y, N, M, origin, CellsCounter): if y < N: (y, N, x, M, origin, CellsCounter) = inner(y, N, x, M, origin, CellsCounter) return outer(y + 1, N, M, origin, CellsCounter) else: return (origin, CellsCounter) Also, the caller of outer won't use y or N or x or M as passed into outer so let's avoid returning those. Let's look at inner some more. def inner(y, N, x, M, origin, CellsCounter): if x < M: if origin[x][y] == 1 and CellsMap[x][y] == 0: CellsCounter += 1 DiscoverCells(origin, x, y, CellsCounter) return inner(y, N, x + 1, M, origin, CellsCounter) else: return (y, N, x, M, origin, CellsCounter) our caller doesn't need us to tell it what y, x, N and M are after we finish our loop iteration so let's not bother returning those values. def inner(y, N, x, M, origin, CellsCounter): if x < M: if origin[x][y] == 1 and CellsMap[x][y] == 0: CellsCounter += 1 DiscoverCells(origin, x, y, CellsCounter) return inner(y, N, x + 1, M, origin, CellsCounter) else: return (origin, CellsCounter) Notice that we no longer use N anywhere so we can eliminate that too. def inner(y, x, M, origin, CellsCounter): if x < M: if origin[x][y] == 1 and CellsMap[x][y] == 0: CellsCounter += 1 DiscoverCells(origin, x, y, CellsCounter) return inner(y, x + 1, M, origin, CellsCounter) else: return (origin, CellsCounter) So our two functions that do recursion are def outer(y, N, M, origin, CellsCounter): if y < N: (origin, CellsCounter) = inner(y, x, M, origin, CellsCounter) return outer(y + 1, N, M, origin, CellsCounter) else: return (origin, CellsCounter) def inner(y, x, M, origin, CellsCounter): if x < M: if origin[x][y] == 1 and CellsMap[x][y] == 0: CellsCounter += 1 DiscoverCells(origin, x, y, CellsCounter) return inner(y, x + 1, M, origin, CellsCounter) else: return (origin, CellsCounter) Now the only variables that "change" between loops are x, y, and CellsCounter so we can use nested functions to avoid passing those as inputs (and because origin doesn't change we can avoid returning that too. def big(N, M, origin): def outer(y, CellsCounter): if y < N: CellsCounter = inner(y, x, CellsCounter) return outer(y + 1, CellsCounter) else: return CellsCounter def inner(y, x, CellsCounter): if x < M: if origin[x][y] == 1 and CellsMap[x][y] == 0: CellsCounter += 1 DiscoverCells(origin, x, y, CellsCounter) return inner(y, x + 1, CellsCounter) else: return CellsCounter return outer(y=0, CellsCounter=0) And likewise if we do another nested definition, inner never changes y so it can just be a closure capturing y from outer. def big(N, M, origin): def outer(y, CellsCounter): def inner(x, CellsCounter): if x < M: if origin[x][y] == 1 and CellsMap[x][y] == 0: CellsCounter += 1 DiscoverCells(origin, x, y, CellsCounter) return inner(x + 1, CellsCounter) else: return CellsCounter if y < N: CellsCounter = inner(x=0, CellsCounter) return outer(y + 1, CellsCounter) else: return CellsCounter return outer(y=0, CellsCounter=0)
2 of 3
1
To all following commenters: please, do not bring up the old circlejerk jokes/memes about recursion ("Understanding recursion...", "This is recursion...", etc.). We've all heard them n+2 too many times. I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.
Top answer
1 of 2
1

but I wonder if it's okay there's no "return" line under "else:"

Yes, that's OK. You don't need to return anything from your function if you don't want to. In fact, in the interest of consistency, you may as well remove the thing returned in the if block too:

def printElement(inputlist):
        newlist=inputlist
        if len(newlist)==0:
                return
        else:
                removedElement=newlist[len(inputlist)-1]
                newlist=newlist[:len(inputlist)-1]
                Element=printElement(newlist)
                print(removedElement)


collection = ['hey', 5, 'd']

printElement(collection)

Is it better code with or without the newlist?

Assigning new things to inputlist won't modify it outside of the function, so there's no harm in doing so. May as well get rid of newlist.

def printElement(inputlist):
        if len(inputlist)==0:
                return
        else:
                removedElement=inputlist[len(inputlist)-1]
                inputlist=inputlist[:len(inputlist)-1]
                Element=printElement(inputlist)
                print(removedElement)


collection = ['hey', 5, 'd']

printElement(collection)

you don't use Element after assigning it, so you may as well not assign it at all.

def printElement(inputlist):
        if len(inputlist)==0:
                return
        else:
                removedElement=inputlist[len(inputlist)-1]
                inputlist=inputlist[:len(inputlist)-1]
                printElement(inputlist)
                print(removedElement)


collection = ['hey', 5, 'd']

printElement(collection)

You don't really need to modify inputlist, since you only use it once after modifying it. Just stick that expression straight into the printElement call. And now that inputlist is never modified, you can get rid of removedElement too, and just inline its expression in the print function.

def printElement(inputlist):
        if len(inputlist)==0:
                return
        else:
                printElement(inputlist[:len(inputlist)-1])
                print(inputlist[len(inputlist)-1])


collection = ['hey', 5, 'd']

printElement(collection)

Fun fact: for any list x, x[len(x)-1] can be shortened to x[-1]. Same with x[:len(x)-1] to x[:-1].

def printElement(inputlist):
        if len(inputlist)==0:
                return
        else:
                printElement(inputlist[:-1])
                print(inputlist[-1])


collection = ['hey', 5, 'd']

printElement(collection)

Since the first block unconditionally returns, you could remove the else and just put that code at the function level, without changing the code's behavior. Some people find this less easy to read. Personally, I like my code to have the least amount of indentation possible.

def printElement(inputlist):
        if len(inputlist)==0:
                return
        printElement(inputlist[:-1])
        print(inputlist[-1])


collection = ['hey', 5, 'd']

printElement(collection)

That's about as compact as you can get, with a recursive solution. You should probably just stick with the iterative version, for a few reasons:

  • Fewer lines
  • More easily understood
  • Doesn't raise a "maximum recursion depth exceeded" exception on lists with 200+ elements
2 of 2
1

Your function is needlessly complicated. The return value is never used. You also print from the end of the list, which is a bit odd: tail recursion is a more usual style. For example:

def printCollection(c):
    if c:
        print c[0]
        printCollection(c[1:])

This still has the flaw that it copies the list for every element in the list, making it an O(n^2) function. It's also limited to data structures that use slices and indices. Here's a recursive version that prints any iterable:

def printCollection(c):
    it = iter(c)
    try:
        el = it.next()
        print el
        printCollection(it)
    except StopIteration:
        pass

It's still a bit odd to recurse here as this is a naturally iterative problem.

🌐
Quora
quora.com › How-would-you-convert-a-recursion-into-a-for-loop
How would you convert a recursion into a for loop? - Quora
This is always can be translated into a loop relatively directly. The algorithms than use the recursion massively are often rewritten in a dif ... It depends. Formally you can always convert a recursion to a while cycle if you have a stack-like structure to emulate the recursion.
🌐
Moertel
blog.moertel.com › posts › 2013-05-11-recursive-to-iterative.html
Tricks of the trade: Recursion to Iteration, Part 1: The Simple Method, secret features, and accumulators - Tom Moertel’s Blog
Convert recursive calls into tail calls. def factorial1a(n, acc=1): if n < 2: return 1 * acc return factorial1a(n - 1, acc * n) (If this step seemed confusing, see the Bonus Explainer at the end of the article for the “secret feature” trick behind the step.) Introduce a one-shot loop around the function body.
🌐
Reddit
reddit.com › r/learnpython › loops vs recursion
r/learnpython on Reddit: Loops vs recursion
April 30, 2018 -

So I was watching this video on youtube and was simply amazed by this function to calculate factorials with recursions.

def factorials(n):
    if n == 1:
        return 1
    else:
        return n * factorial(n-1)

Since I'm pretty new to python and coding in general (I'm a lawyer by profession), I would have solved this problem with loops. The moment I understood the concept of this function, I was baffled by the simplicity and beauty of it.

Now here's my question:

  1. In which cases is it smarter to use one or the other and what are the benefits? (if there even is a general rule)

  2. Where can I learn more about recursions? Are there any tutorials online?

Thanks :)

Top answer
1 of 5
36
Every recursive solution can be expressed as a loop, and vice versa. In Python, you use recursion when the recursive solution makes it easier to understand (you would probably use a loop for a factorial) Recursions are heavily used in functional programming (which Python does not excel at), and Guido said he prefers loops instead of recursion. If you like recursion and mathematical elegance in programming, I recommend you take a look at functional programming and functional programming languages. Be advised though that functional programming can be difficult to grasp at first.
2 of 5
20
You CAN solve almost any problem using almost any loop. But when is it more appropriate to use which loop, my opinion is this: A while loop is the correct solution when the data amount and endpoint is unknown. A for loop is the correct solution when the amount of data, and endpoint is known. A Recursion is the correct solution when the amount is known, but the end point is not. So what I mean by that is, imagine finding a file in a bunch of folders. Inside every folder the AMOUNT of files are known, so you use a for loop to walk through the files and you pick out the right file. But how many folders do you need to go through? You don't know that, because every subfolder COULD have another subfolder, or not. And so the folder structure branches out, in an unknown way. This becomes difficult to deal with using multiple for loops. Again, because the endpoint is unknown. Here recursion is the perfect solution. find_file(folder): global filelist for file in folder.files: if ".jpg" in file.name: filelist.append(file) for subfolder in folder.dirs: find_file(subfolder)
🌐
Stack Overflow
stackoverflow.com › questions › 74649471 › convert-loop-to-recursive-function
python - Convert loop to recursive function - Stack Overflow
If you print out just for value 5 you get 1+3+9+33+153 where !5=120 Which is the way you're trying to accomplish it? ... Minor quibble: if you change that list comp to a generator expression (removing the [ and ]), it'll accomplish the same thing without first storing the whole list in memory. The bigger issue, however, is that you're not calculating the same thing that the asker is. ... def recursive_sum(a, b, res=0): if a > b: return res temp = 1 for j in range(1, a+1): temp = temp * j res = res + temp return recursive_sum(a+1, b, res) a = int(input("Please enter the first number: ")) b = int(input("Please enter the second number: ")) res = recursive_sum(a, b) print(f"Sum of products from 1 to each integer in the range {a} to {b} is: {res}")
Top answer
1 of 2
5

The standard structural recursive formula (and the one you'd use if you were using a functional language like Scheme) would be to deconstruct the list recursively:

func([]) => nothing
func([x, ...]) => do_stuff(x), func([...])

Therefore, the "functional" way to do this would be to take a single list (not an index), and to recurse on smaller lists:

def rec_list(l):
    if not l: return # empty list case
    # process l[0]
    return rec_list(l[1:])

Note that this is terribly, terribly inefficient because of the l[1:], but it's the basis for understanding more complex recursive constructs (e.g. recursing on binary trees).

We can do interesting things with this kind of structural recursion. For example, here's how you'd reverse a list in a functional language:

def rev_list(l):
    if not l: return []
    return rev_list(l[1:]) + [l[0]]

(Of course, you could just do l[::-1] in Python, but here we're trying to show how it would be done recursively).

2 of 2
1

So you want to do away with a nice (mostly) well coded loop? (mostly because you probably want to use enumerate instead of range(len(lst))) -- enumerate is pretty cool, once you start using it, you'll never look back.

Anyway, I guess we can do that:

def silly_loop(lst,index=0):
    try:
       #do something with index and lst here
       silly_loop(lst,index=index+1)
    except IndexError:  #or maybe a different error, depending on what you're doing with index ...
       return

an example:

def silly_loop(lst,index=0):
    try:
       print lst[index]
       silly_loop(lst,index=index+1)
    except IndexError:
       return

a = range(10)
silly_loop(a)

Note that I can't think of ANY reason why you would want to do this in real code, (But, if you're just doing this to teach yourself about recursion, then I hope this helps).

🌐
Open Computing Facility
ocf.berkeley.edu › ~shidi › cs61a › wiki › Iteration_vs._recursion
Iteration vs. recursion - CS 61A Wiki
A tail recursive function can be converted to an iterative function using the same idea as above. A more complicated recursive function will require a stack to convert to an iterative function. This is outside the scope of 61A. http://www.fbeedle.com/python/99-6ch13.pdf (section 13.2.7)
🌐
GeeksforGeeks
geeksforgeeks.org › python › recursion-in-python
Recursion in Python - GeeksforGeeks
Tail Recursion: The recursive call is the last thing the function does, so nothing happens after it returns. Some languages can optimize this to work like a loop, saving memory.
Published   1 week ago
🌐
YouTube
youtube.com › watch
How to Write Recursion Instead of For/While Loop - YouTube
Hi everyone! In this video, I will show you how to write a function using recursion instead of for loop or a while loop. In other words, I show you how to co...
Published   April 25, 2022
🌐
Quora
quora.com › What-are-the-different-ways-of-turning-2-for-loops-into-a-recursive-function
What are the different ways of turning 2 for loops into a recursive function? - Quora
November 9, 2019 - Answer (1 of 2): Say you’ve got ... turn a loop into “primitive recursion” where the first argument of the recursive function takes the place of the loop index: [c......