Given a word, how can I use use it or lose it recursion to return all possible combinations of these letters?

Question:

I want to make a recursive function called makeCombinations that will take in an input a string and return all possible combinations of its letters as a list. So far I have this:

def delist(l):
    '''delist takes in input list l and if it its a nested list returns a new list that de-nests all the lists. Ex: [1,2,[3,4]] -> [1,2,3,4]'''
    if(l == []):
        return []
    else:
        if(isinstance(l[0], list)):
            return delist(l[0]) + delist(l[1:])
        else:
            return [l[0]] + delist(l[1:])

 
def makeCombinations(word, currentString=''):
    if(word == ''):
        return currentString
    else:
        use_it = makeCombinations(word[1:], currentString = currentString + word[0])
        lose_it = makeCombinations(word[1:], currentString)
        return delist([use_it , lose_it])
print(makeCombinations("asmtp"))

When running makeCombinations it returns:

['asmtp', 'asmt', 'asmp', 'asm', 'astp', 'ast', 'asp', 'as', 'amtp', 'amt', 'amp', 'am', 'atp', 'at', 'ap', 'a', 'smtp', 'smt', 'smp', 'sm', 'stp', 'st', 'sp', 's', 'mtp', 'mt', 'mp', 'm', 'tp', 't', 'p', '']

Which is pretty close, however it isn’t all, and I am actually looking for very specific words, "a", "at", "am", but also, "spam" which for some reason just wont be outputted. I feel like this is due to the fact I am only taking the right side and not checking the reverse case, but I am not sure how to do this. I can’t use loops or itertools.

Asked By: Cr3 D

||

Answers:

Is this what you want?

from itertools import permutations

def makeCombinations(word):
    return [''.join(p) for n in range(len(word))
            for p in permutations(word, n + 1)]

print(makeCombinations("asmtp"))


['a', 's', 'm', 't', 'p', 'as', 'sa', 'am', 'ma', 'at', 'ta', 'ap', 'pa', 'sm', 'ms', 'st', 'ts', 'sp', 'ps', 'mt', 'tm', 'mp', 'pm', 'tp', 'pt', 
    ... 'ptsma', 'ptmas', 'ptmsa']

Sorry it’s not recursive.

Answered By: Bill

I think the use-it, lose-it algorithm is for finding all combinations (i.e. unique sets of letters). Because you say the order of the letters in the word is important, I think you are looking for all permutations (i.e. unique words).

Here’s how you would find all combinations:

def makeCombinations(word, currentString=''):
    if(word == ''):
        return [currentString]
    use_it = makeCombinations(word[1:], currentString=currentString + word[0])
    lose_it = makeCombinations(word[1:], currentString)
    return use_it + lose_it

print(makeCombinations("abc"))
['abc', 'ab', 'ac', 'a', 'bc', 'b', 'c', '']

You could write a makePermutations(word) function and call that on each combination result:

def flatten_list(l):
    return [item for sublist in l for item in sublist]

def makePermutations(word, currentString=''):
    if(word == ''):
        return [currentString]
    return flatten_list([
        makePermutations(word.replace(a, ''), currentString=currentString + a)
        for a in word
    ])

assert(makePermutations("abc") == ['abc', 'acb', 'bac', 'bca', 'cab', 'cba'])

def makeAllPermutations(word, currentString=''):
    if(word == ''):
        return makePermutations(currentString)
    use_it = makeAllPermutations(word[1:], currentString=currentString + word[0])
    lose_it = makeAllPermutations(word[1:], currentString)
    return use_it + lose_it

print(makeAllPermutations("abc"))
['abc', 'acb', 'bac', 'bca', 'cab', 'cba', 'ab', 'ba', 'ac', 'ca', 'a', 'bc', 'cb', 'b', 'c', '']

However I used a list comprehension here so you’d have to add another level of recursion to eliminate that.

I think you might be able to combine makePermutations and makeAllPermutations functions into one but not sure.

Answered By: Bill