2

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.

Community
  • 1
  • 1
agtoever
  • 1,669
  • 16
  • 22
  • 5
    `lastdigits = generate_combinations( *args[1:] )` – parchment Oct 31 '14 at 09:12
  • 1
    [Pass elements of a list as arguments to a function in python](http://stackoverflow.com/questions/2756116/pass-elements-of-a-list-as-arguments-to-a-function-in-python) – parchment Oct 31 '14 at 09:13

1 Answers1

4

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.

Arthur Vaïsse
  • 1,551
  • 1
  • 13
  • 26
  • Learned a lot! Thank you very much! Could you just explain why the `tuple` is needed? I understand the `*`, but why add the `tuple` in the line where the function is called recursively? – agtoever Oct 31 '14 at 09:37
  • 1
    There's no need for that - you can unpack lists with `*` too – jonrsharpe Oct 31 '14 at 09:40
  • For future reference, I think it's because the complete definition of a variable argument function is `def f( *args, **kwargs )`. I assume the tuple refers to the args and kwargs tuple (please correct me if I'm wrong). – agtoever Oct 31 '14 at 09:45
  • 1
    no jonrsharpe is good, there is no need for the tuple. I edited my code for completeness reasons. Added **kwargs that aren't use to show you how to handle **keywordargs too. – Arthur Vaïsse Oct 31 '14 at 09:49