How to get all subsets of a set? (powerset)

前端 未结 28 2465
庸人自扰
庸人自扰 2020-11-22 05:18

Given a set

{0, 1, 2, 3}

How can I produce the subsets:

[set(),
 {0},
 {1},
 {2},
 {3},
 {0, 1},
 {0, 2},
 {0, 3},
 {1, 2}         


        
相关标签:
28条回答
  • 2020-11-22 05:41

    Getting all the subsets with recursion. Crazy-ass one-liner

    from typing import List
    
    def subsets(xs: list) -> List[list]:
        return subsets(xs[1:]) + [x + [xs[0]] for x in subsets(xs[1:])] if xs else [[]]
    

    Based on a Haskell solution

    subsets :: [a] -> [[a]]
    subsets [] = [[]]
    subsets (x:xs) = map (x:) (subsets xs) ++ subsets xs
    
    0 讨论(0)
  • 2020-11-22 05:42

    Use function powerset() from package more_itertools.

    Yields all possible subsets of the iterable

    >>> list(powerset([1, 2, 3]))
    [(), (1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]
    

    If you want sets, use:

    list(map(set, powerset(iterable)))
    
    0 讨论(0)
  • 2020-11-22 05:44

    If you want any specific length of subsets you can do it like this:

    from itertools import combinations
    someSet = {0, 1, 2, 3}
    ([x for i in range(len(someSet)+1) for x in combinations(someSet,i)])
    

    More generally for arbitary length subsets you can modify the range arugment. The output is

    [(), (0,), (1,), (2,), (3,), (0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3), (0, 1, 2), (0, 1, 3), (0, 2, 3), (1, 2, 3), (0, 1, 2, 3)]

    0 讨论(0)
  • 2020-11-22 05:48

    Here is more code for a powerset. This is written from scratch:

    >>> def powerset(s):
    ...     x = len(s)
    ...     for i in range(1 << x):
    ...         print [s[j] for j in range(x) if (i & (1 << j))]
    ...
    >>> powerset([4,5,6])
    []
    [4]
    [5]
    [4, 5]
    [6]
    [4, 6]
    [5, 6]
    [4, 5, 6]
    

    Mark Rushakoff's comment is applicable here: "If you don't like that empty tuple at the beginning, on."you can just change the range statement to range(1, len(s)+1) to avoid a 0-length combination", except in my case you change for i in range(1 << x) to for i in range(1, 1 << x).


    Returning to this years later, I'd now write it like this:

    def powerset(s):
        x = len(s)
        masks = [1 << i for i in range(x)]
        for i in range(1 << x):
            yield [ss for mask, ss in zip(masks, s) if i & mask]
    

    And then the test code would look like this, say:

    print(list(powerset([4, 5, 6])))
    

    Using yield means that you do not need to calculate all results in a single piece of memory. Precalculating the masks outside the main loop is assumed to be a worthwhile optimization.

    0 讨论(0)
  • 2020-11-22 05:48

    You can do it like this:

    def powerset(x):
        m=[]
        if not x:
            m.append(x)
        else:
            A = x[0]
            B = x[1:]
            for z in powerset(B):
                m.append(z)
                r = [A] + z
                m.append(r)
        return m
    
    print(powerset([1, 2, 3, 4]))
    

    Output:

    [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3], [4], [1, 4], [2, 4], [1, 2, 4], [3, 4], [1, 3, 4], [2, 3, 4], [1, 2, 3, 4]]
    
    0 讨论(0)
  • 2020-11-22 05:49

    A simple way would be to harness the internal representation of integers under 2's complement arithmetic.

    Binary representation of integers is as {000, 001, 010, 011, 100, 101, 110, 111} for numbers ranging from 0 to 7. For an integer counter value, considering 1 as inclusion of corresponding element in collection and '0' as exclusion we can generate subsets based on the counting sequence. Numbers have to be generated from 0 to pow(2,n) -1 where n is the length of array i.e. number of bits in binary representation.

    A simple Subset Generator Function based on it can be written as below. It basically relies

    def subsets(array):
        if not array:
            return
        else:
            length = len(array)
            for max_int in range(0x1 << length):
                subset = []
                for i in range(length):
                    if max_int & (0x1 << i):
                        subset.append(array[i])
                yield subset
    

    and then it can be used as

    def get_subsets(array):
        powerset = []
        for i in subsets(array):
            powerser.append(i)
        return powerset
    

    Testing

    Adding following in local file

    if __name__ == '__main__':
        sample = ['b',  'd',  'f']
    
        for i in range(len(sample)):
            print "Subsets for " , sample[i:], " are ", get_subsets(sample[i:])
    

    gives following output

    Subsets for  ['b', 'd', 'f']  are  [[], ['b'], ['d'], ['b', 'd'], ['f'], ['b', 'f'], ['d', 'f'], ['b', 'd', 'f']]
    Subsets for  ['d', 'f']  are  [[], ['d'], ['f'], ['d', 'f']]
    Subsets for  ['f']  are  [[], ['f']]
    
    0 讨论(0)
提交回复
热议问题