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

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
[Python] Converting Nested For-Loop into Recursion
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) More on reddit.com
🌐 r/learnprogramming
4
1
February 17, 2020
python - How can I replace a nested for loop with recursion? - Stack Overflow
First of all, I'm still a newb to python so please take it easy on me. I've done my research and I have a basic understanding of how to write a recursive function, but I'm totally confused at the... More on stackoverflow.com
🌐 stackoverflow.com
January 10, 2014
Converting a for loop to recursion in Python - Stack Overflow
Recursive case: Involves calling the function again, corresponds to one for loop in your code. More on stackoverflow.com
🌐 stackoverflow.com
October 29, 2016
🌐
Educative
educative.io › home › converting iterative code to recursive code
Converting Iterative Code to Recursive Code
Let’s have a look at an example: ... It should return a result based on the final values. Use the loop condition as the base case and the body of the loop as the recursive case. The local variables in the iterative version turn into parameters ...
🌐
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.
🌐
Educative
educative.io › home › courses › recursion for coding interviews in python › converting iterative code to recursive code
How to Convert Iterative Code to Recursive Code in Python
Let’s take a look at an example: ... It should return a result based on its final values. Use the loop condition as the base case and the body of the loop as the recursive case. The local variables in the iterative version turn into the parameters ...
Find elsewhere
🌐
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...
🌐
Refactoring
refactoring.com › catalog › replaceIterationWithRecursion.html
Replace Iteration with Recursion - Refactoring
(it is, of course, possible to ... readability/simplicity advantages of the recursive version) Identify the candidate loop. The loop should modify one or more scoped locals, and then return a result based on their final values. Move the loop into a new function....
🌐
LabEx
labex.io › tutorials › python-how-to-transform-recursion-to-loops-434273
How to transform recursion to loops | LabEx
Learn efficient Python techniques to convert recursive functions into iterative loops, improving code performance and reducing memory overhead.
🌐
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.
🌐
W3Schools
w3schools.com › python › gloss_python_function_recursion.asp
Python Function Recursion
Python also accepts function recursion, which means a defined function can call itself. Recursion is a common mathematical and programming concept. It means that a function calls itself. This has the benefit of meaning that you can loop through data to reach a result. The developer should be very careful with recursion as it can be quite easy to slip into writing a function which never terminates, or one that uses excess amounts of memory or processor power.
🌐
Wordpress
argandgahandapandpa.wordpress.com › 2008 › 03 › 27 › turning-a-while-loop-into-a-recursive-function
Turning a while loop into a recursive function | Arg and gah and ap and pa
May 5, 2011 - def loop_func(state, constants): if condition(state): return loop_func(f(state, constants), constants) else: return state state = loop_func(init_state, init_constants)
🌐
Programiz
programiz.com › python-programming › recursion
Python Recursion (Recursive Function)
In this tutorial, you will learn to create a recursive function (a function that calls itself).
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"))
🌐
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......