Search code examples
pythonrecursionoptional-arguments

Variable number of arguments and recursion in Python


I wanted to write a recursive function that takes a variable number of arguments (each argument being an iterable list or set) and returns a set of all concatenated combinations of each argument. I learned how to write functions with a variable number of arguments and I know how to write recursive functions, but I don't know how to put those two together in Python (or if it is even possible).

Here's my code:

def generate_combinations( *args ):
    # returns all combinations of each of the arguments
    if len( args ) == 1:
        return set( args[0] )

    result = set()
    lastdigits = generate_combinations( args[1:] )
    for d in args[0]:
         result.add( d + lastdigits )      

if __name__ == '__main__':
    lastDigit = [ '1', '2', '3' ]
    allDigits = [ '4', '5' ]
    print("{}".format( generate_combinations( allDigits, lastDigit )))

Expected output:

14
15
24
25
34
35

The "problem" with my code lies in line 7: lastdigits = generate_combinations( args[1:] ). What I wanted to do here, is to pass all original arguments except the first one to the function (thus creating the recursion). And this is obviously not the way to do that. My question: can this be done, and how?

Ps: I know I can accomplish the same using a list of lists with one argument, but I'm curious is this is at all possible.


Solution

  • The requested job is done by these lines :

    args = list(args)
    args.pop(0)
    recursiveCall( *tuple(args) )
    

    Here the implementation of your function was a little buggy ( or I misunderstand your use of set maybe ).

    def generate_combinations( *args, **kwargs ):
        print("called with", args)
        #terminate recursion
        if len(args) == 1:
            return list(set(args[0]))
    
        #recursion
        else:
            result = []
            args = list(args)
            heads = args.pop(0)
            tails = generate_combinations( *args, **kwargs )
            for head in heads:
                for tail in tails:
                    result.append(head + tail)
            return result
    
    if __name__ == '__main__':
        allDigits = [ '1', '2', '3' ]
        lastDigit = [ '4', '5' ]
        letters   = [ 'a', 'b' ]
        print("{}".format( generate_combinations( allDigits, lastDigit, letters , Useless='parameter')))
    

    Execution give :

    ['14a', '14b', '15a', '15b', '24a', '24b', '25a', '25b', '34a', '34b', '35a', '35b']
    

    Hope you enjoy this ;)

    Arthur.