Unexpected results when using recursion

recursive function example
recursive function python
recursive functions in c
recursive function definition
recursive function c++
recursion using stack
recursive function javascript
recursion in data structure

I've just started to get into the world of python and frankly, I'm a little bit confused about the results the following implementation gives me.

It's just a recursive function that should output all of the permutations of a given list. I know there's probably a thousand better ways of doing the same, but this is what I came up with. What strikes me is that the exact same code works just fine in C++; I believe it may have something to do with the way variables are passed in python*, but I'm not sure.

The code:

def permut (s, permut_s):
    if not s:
        return permut_s
    if not permut_s:
        last_s = s[-1]
        s.pop (-1)
        permut_s = [[last_s]]
        return permut (s, permut_s)
    new_permut_s = []
    last_s = s[-1]
    for x in range (len (permut_s)):
        aux = permut_s[x]
        aux = [last_s] + aux
        new_permut_s.append (aux)
        for y in range (len (aux) - 1):
            aux_elem = aux[y]
            aux[y] = aux[y + 1]
            aux[y + 1] = aux_elem
            new_permut_s.append (aux)
    s.pop (-1)
    return permut (s, new_permut_s)

def main(s, permut_s):
    print (permut (s, permut_s))

main ([1,2,3], [])

*the reason I say this is because doing some prints in between lines shows that before the first non-trivial execution, new_permut_s = [[2,3]], and after, it is [[3,2],[3,2]], when it should be [[2,3],[3,2]]

Thanks a lot !

The issue is that you append the same list several times. So your modifications affect previous new_permut_s elements (as they all can be seen as the same address of the list as the one in aux). The simplest solution is the following (see # THE FIX):

def permut (s, permut_s):
    if not s:
        return permut_s
    if not permut_s:
        last_s = s[-1]
        s.pop (-1)
        permut_s = [[last_s]]
        return permut (s, permut_s)
    new_permut_s = []
    last_s = s[-1]
    for x in range (len (permut_s)):
        aux = permut_s[x]
        aux = [last_s] + aux
        new_permut_s.append (aux)
        for y in range (len (aux) - 1):
            aux = aux[:]  # THE FIX
            aux_elem = aux[y]
            aux[y] = aux[y + 1]
            aux[y + 1] = aux_elem
            new_permut_s.append (aux)
    s.pop (-1)
    return permut (s, new_permut_s)

def main(s, permut_s):
    print (permut (s, permut_s))

main ([1,2,3], [])

By aux = aux[:] (or aux = aux[0:len(aux)]), we take the original list, take its slice (which is always a new object, at least in the standard library) and then assign the slice (a list here) to the same variable.

As for if this copying can be avoided: I don't think so, since lists for all permutations should be independent. Theoretically you can write a class to patch existing lists (such that each instance holds the reference to a "global" list and some local patch, and then the actual value is calculated for an index when it's accessed), or you can merge the code for copying and for swapping (such that you copy several parts of the original list in several steps). But such solutions seem to be overkill for your task.


PythonTutor.com helps to debug such issues. Particularly, I used this "visualization" to debug your code.

In the REPL, such checks are useful:

>>> out = permut([1,2,3], [])
>>> out[0] is out[1]
True

Unexpected Random behaviour in Recursive Function., Running this rule results in a list of different random numbers each time. This seems to rule out any issues with rand() and recursion. Fullscreen. 1. 2. 3. Stack Exchange network consists of 175 Q&A communities including Stack Overflow, the largest, most trusted online community for developers to learn, share their knowledge, and build their careers.

Forget all the permutations you can use:

import itertools
list(itertools.permutations([1, 2, 3]))

"Don't reinvent the wheel" is one of the best adages in programming.

Learning C++ Functional Programming, Chapter 4, Repeating Method Invocation Using Recursive Algorithm, if there are unexpected results or the program crashes in the middle of execution. At the end recursion, it returns the final result value and finally the stack gets destroyed and memory is freed up. If the recursion fails to reach a base case, then the stack will rapidly be exhausted leading to Stack Overflow crash.

You are appending shallow copies to your output. Use this:

from copy import deepcopy

def permut (s, permut_s):
    print(s)
    print(permut_s)
    if not s:
        return permut_s
    if not permut_s:
        last_s = s[-1]
        s.pop (-1)
        permut_s = [[last_s]]
        return permut (s, permut_s)
    new_permut_s = []
    last_s = s[-1]
    for x in range (len (permut_s)):
        aux = permut_s[x]
        aux = [last_s] + aux
        new_permut_s.append (deepcopy(aux))
        for y in range (len (aux) - 1):
            aux_elem = aux[y]
            aux[y] = aux[y + 1]
            aux[y + 1] = aux_elem
            new_permut_s.append (deepcopy(aux))
    print("new")
    print(new_permut_s)
    s.pop (-1)
    return permut (s, new_permut_s)

def main(s, permut_s):
    print (permut (s, permut_s))

main ([1,2,3], [])

The Neural Architecture of Grammar, Recursion Recursion involves the process of inserting (embedding) Among the unexpected results of taking a connectionist approach to grammar is the  Disadvantages  Can cause infinite loops and other unexpected results if not written properly.  If the end condition is not defined then the recursion will repeat forever, causing the program to crash or hang the entire computer system. Tower Of Hanoi (TOH)  It can be solved by using recursion technique.

Recursive Functions, results in optimal time complexity using recursion. Base Case: One critical Missing base case results in unexpected behaviour. Different Ways of Writing  In recursive backtracking, if one set of recursive calls does not result in a solution to the problem, what happens? a. The program returns to a previous decision point and makes a different decision. b. The program backs up to the previous decision point and throws an exception. c. The program continues, with unexpected results. d.

Recursion, However, fundamentally, using recursion is more than that -- it is a powerful way to If you mutate those values, you will get unexpected results, where it works  Start studying CS 1337 Final Exam. Learn vocabulary, terms, and more with flashcards, games, and other study tools.

The Mathematica GuideBook for Programming, However, the price of always using : = is possibly a definite loss of efficiency, It too leads to a recursion error. This process may lead to unexpected results. The recursion pattern appears in many scenarios in the real world, and we’ll cover some examples of recursion in Python here. A recursive function just keeps calling itself until it has completed the problem at hand. That brings up a good point, and that is to make sure that your recursive function actually terminates and returns at some point.

Comments
  • When you swap the aux you also swap the same aux you appended to new_permut_s before that. You should make a deepcopy of the list first. (import deepcopy from copy)
  • Thanks. Is there a way to append somethin as a "copy" to avoid this issue? And could you clarify what aux = aux[:] does?
  • aux = aux[:] just makes a shallow copy. So, the returned permutations in the end will contain values which all point to the same object. For some usages this would be problematic.
  • @HielkeWalinga A permutation is (by definition) a rearrangement of existing elements themselves (1, 2) rather than their copies. So deep copying is not only always slower, but it's also functionally incorrect for permutations (if it's not equivalent to shallow copying). If the goal were to get not permutations but something similar, then deep copying might be OK.
  • @KirillBulygin Okay, good to know. I checked, and the one from itertools is also implemented with shallow copying.
  • Thanks for your answer. It's not that I want to reinvent anything or use this function in any production. As I said, I'm new to python and just trying out stuff, and knowing why this does not work might help me, and possibly others, to stop making the same mistake in real case scenarios.