Get all possible subsets from a set of distinct integers using OOP An assignment at school required me to write a program for this task:


  
  Create a class and define two methods in the class.
  Method f1 is used to pass an empty list and the sorted list is taken from the user to method f2.
  Method f2 is used to compute all possible subsets of the list.
  Then the result is returned from the function and printed.
  Exit
  


Here is my solution to this task, using Python:

class sub:  
    def f1(self, s1):  
        return self.f2([], sorted(s1))  

    def f2(self, current, s1):  
        if s1:  
            return self.f2(current, s1[1:]) + self.f2(current + [s1[0]], s1[1:])  
        return [current]  
a = []
n = int(input("Enter number of elements of list: "))
for i in range(0,n):
    b = int(input("Enter element: "))
    a.append(b)
print ("Subsets: ")
print (sub().f1(a))


NOTE - Method f2 is a recursive function.

Here are some example inputs and outputs:

Enter number of elements of list: 2
Enter element: 4
Enter element: 5
Subsets: 
[[], [5], [4], [4, 5]]

Enter number of elements of list: 4
Enter element: 3
Enter element: 5
Enter element: 7
Enter element: 28
Subsets: 
[[], [28], [7], [7, 28], [5], [5, 28], [5, 7], [5, 7, 28], [3], [3, 28], [3, 7], [3, 7, 28], [3, 5], [3, 5, 28], [3, 5, 7], [3, 5, 7, 28]


So, I would like to know whether I could make this program shorter and more efficient.

Any help would be highly appreciated.
I. This chunk of code:

a = []
n = int(input("Enter number of elements of list: "))
for i in range(0,n):
    b = int(input("Enter element: "))
    a.append(b)


is mostly C-like (or Pascal-like etc). You can replace it with more Pythonic:

a = input('Enter elements splitted by ":" ').split(' ')

II. Here:

print (sub().f1(a))

You are creating a sub instance within the print function. It is a bad idea because it will disappear after print. You should create it before you print something (and, yes, classes names in Python are in CamelCase):

waka = Sub()
print(waka.f1(a))


III. I prefer to create __init__() function each time I create a class. It is not really necessary but in most cases, it is the first one is creating in the new class:

class Sub(object):
    def __init__(self):
        pass


IV. If it is your homework you should do with recursion, the code is pretty OK. In another case, I recommend you to use Python itertools module (you should avoid recursion as much as possible):

    def f2(self, current, s1):  
        return [
            e
            for e in itertools.chain.from_iterable([
                [sorted(l) for l in itertools.combinations(s1, length)]
                for length in range(1, len(s1))
            ])
        ]


So here is the result code for recursion version:

class Sub(object):
    def __init__(self):
        pass

    def f1(self, s1):  
        return self.f2([], sorted(s1))  

    def f2(self, current, s1):  
        if s1:  
            return self.f2(current, s1[1:]) + self.f2(current + [s1[0]], s1[1:])  
        return [current]

a = input('Enter elements splitted by " ": ').split(' ')
waka = Sub()
print(waka.f1(a))