1

I'm trying to write python code to print the powerset of a string, but am running into some bugs. Here's what I've got:

def getperm (string):
    perm = []
    if len(string) == 0:
        perm.append("")
        return perm
    #if len(string) == 1:
    #   perm.append(string)
    #   perm.append("")
    first = string[0]
    print "first = " + str(first)
    rem = string[1:len(string)]
    print "rem = " + str(rem)
    words = getperm(rem)
    for word in words:
        for i in range(len(word)):
            temp = string[0:i] + first + string[i:len(string)]
            print "temp = " + str(temp)
            perm.append(temp)

    return perm

if __name__=="__main__":
    a = "ab"
    mag  = getperm(a)
    print mag

My expected output would be:

['', 'a', 'b', 'ab']

My actual output is:

[]

Can anyone help me figure out what's going on? Is this some nuance of python, or is there a bug in my code? I think my code should be ok -- I'm going off the fifth edition of Cracking the coding interview

Thank you!

John La Rooy
  • 295,403
  • 53
  • 369
  • 502
mythander889
  • 915
  • 5
  • 16
  • 23
  • 3
    You're looking to generate the power set, not permutations. The only permutations of the string `'ab'` are `'ab'` and `'ba'`. – Matt Ball Sep 28 '12 at 01:34
  • 1
    Also, you really shouldn't name a string `string` (that's the name of a built-in module), and I'm not sure what you're trying to accomplish by calling `str` on objects that are already strings (`first`, `rem`, etc.). – abarnert Sep 28 '12 at 01:36
  • @Matt Ball Yes -- good call. Even so, I'm not generating 'ab' or 'ba'. Do you know why? – mythander889 Sep 28 '12 at 01:37
  • @abarnert Very true -- I renamed string to something different, and removed the redundant str() but am still receiving the errors. Any idea why? – mythander889 Sep 28 '12 at 01:39
  • Well, obviously those weren't causing your problems; they were just making it harder to read… Meanwhile, you should update the question with the edited version of the code. – abarnert Sep 28 '12 at 01:42
  • I changed the title of the question, since the output you are expecting is the powerset. permutations means something different – John La Rooy Sep 28 '12 at 02:23

6 Answers6

4

You're overthinking it

This part is trying to do too much

for word in words:
    for i in range(len(word)):
        temp = string[0:i] + first + string[i:len(string)]
        print "temp = " + str(temp)
        perm.append(temp)

See how simple it really should be

def get_powerset (string):
    perm = []
    if len(string) == 0:
        perm.append("")
        return perm
    #if len(string) == 1:
    #   perm.append(string)
    #   perm.append("")
    first = string[0]
    print "first = " + str(first)
    rem = string[1:len(string)]
    print "rem = " + str(rem)
    words = get_powerset(rem)
    perm.extend(words)
    for word in words:
        perm.append(first+word)

    return perm

if __name__=="__main__":
    a = "ab"
    mag  = get_powerset(a)
    print mag

Now you should be able to make the code look a lot nicer with a little refactoring

John La Rooy
  • 295,403
  • 53
  • 369
  • 502
3

Is this what you want?

import itertools as it

def func(s):
    for i in range(len(s)+1):
        for combo in it.combinations(s,i):
            yield "".join(combo)

print list(func("abc"))
mgilson
  • 300,191
  • 65
  • 633
  • 696
2

Here's a refactored iterative solution without the itertools module:

def powerset(s):
    a = ['']
    for i,c in enumerate(s):
        for k in range(2**i):
            a.append(a[k]+c)
    return a
orwinmc
  • 168
  • 1
  • 13
1

There are a method for permutations:

>>> import itertools
>>> chars = "ABCD"
>>> perms = list(itertools.permutations(chars))
>>> print(perms)
[('A', 'B', 'C'),
 ('A', 'C', 'B'),
 ('B', 'A', 'C'),
 ('B', 'C', 'A'),
 ('C', 'A', 'B'),
 ('C', 'B', 'A')]
Pedro Lacerda
  • 1,098
  • 9
  • 23
0

Have you tried tracing through what your algorithm actually does?

getperm('ab'):
  first, rem = 'a', 'b'
  words = getperm('b')
    first, rem = 'b', ''
    words = getperm('')
    words = ['']
    for word in words:
      for i in range(len(word)):
        pass # only called on '', so doesn't matter
    return []
  words = []
  for word in words:
    pass # only called on [], so doesn't matter

So, there's no nuance of Python here; your algorithm returns the empty list in O(N) steps, and you've coded that algorithm properly in Python.

(Instead of tracing it by hand, of course, you can add some more useful print statements and see what each step is actually doing.)

It probably wasn't the algorithm you wanted, but you'll need to tell us what you were trying to do. Are you, e.g., porting some pseudocode from Hoare into Python? If so, what's the pseudocode?

abarnert
  • 354,177
  • 51
  • 601
  • 671
0

Use powerset from more_itertools:

>>> import more_itertools

>>> ["".join(p) for p in list(more_itertools.powerset("ab"))]
['', 'a', 'b', 'ab']

This powerset is a convenience function directly implemented from the itertools recipes.

pylang
  • 40,867
  • 14
  • 129
  • 121