Search code examples
pythonlistcombinationspython-itertools

Python: breaking a list into all possible sublists


Lets assume I've got a list of integers:

mylist = [101, 102, 103, 104, 105, 106]

Now I need to create every possible sublist division (order preserved):

sublists = [([101], [102, 103, 104, 105, 106]),
            ([101, 102], [103, 104, 105, 106]),
            ([101, 102, 103], [104, 105, 106]),
            ...
            ([101, 102], [103, 104], [105, 106]),
            ...
            ([101], [102, 103, 104], [105], [106]),
            ...
            ([101], [102], [103], [104], [105], [106])]

Any idea? Would itertools be helpful?


Solution

  • You are creating slice points; are you slicing after the current element or not. You can generate these with booleans:

    from itertools import product
    
    def sublists(lst):
        for doslice in product([True, False], repeat=len(lst) - 1):
            slices = []
            start = 0
            for i, slicehere in enumerate(doslice, 1):
                if slicehere:
                    slices.append(lst[start:i])
                    start = i
            slices.append(lst[start:])
            yield slices
    

    Demo:

    >>> from pprint import pprint
    >>> mylist = [101, 102, 103, 104, 105, 106]
    >>> pprint(list(sublists(mylist)))
    [[[101], [102], [103], [104], [105], [106]],
     [[101], [102], [103], [104], [105, 106]],
     [[101], [102], [103], [104, 105], [106]],
     [[101], [102], [103], [104, 105, 106]],
     [[101], [102], [103, 104], [105], [106]],
     [[101], [102], [103, 104], [105, 106]],
     [[101], [102], [103, 104, 105], [106]],
     [[101], [102], [103, 104, 105, 106]],
     [[101], [102, 103], [104], [105], [106]],
     [[101], [102, 103], [104], [105, 106]],
     [[101], [102, 103], [104, 105], [106]],
     [[101], [102, 103], [104, 105, 106]],
     [[101], [102, 103, 104], [105], [106]],
     [[101], [102, 103, 104], [105, 106]],
     [[101], [102, 103, 104, 105], [106]],
     [[101], [102, 103, 104, 105, 106]],
     [[101, 102], [103], [104], [105], [106]],
     [[101, 102], [103], [104], [105, 106]],
     [[101, 102], [103], [104, 105], [106]],
     [[101, 102], [103], [104, 105, 106]],
     [[101, 102], [103, 104], [105], [106]],
     [[101, 102], [103, 104], [105, 106]],
     [[101, 102], [103, 104, 105], [106]],
     [[101, 102], [103, 104, 105, 106]],
     [[101, 102, 103], [104], [105], [106]],
     [[101, 102, 103], [104], [105, 106]],
     [[101, 102, 103], [104, 105], [106]],
     [[101, 102, 103], [104, 105, 106]],
     [[101, 102, 103, 104], [105], [106]],
     [[101, 102, 103, 104], [105, 106]],
     [[101, 102, 103, 104, 105], [106]],
     [[101, 102, 103, 104, 105, 106]]]
    

    If you want to drop the last entry (containing a list with only one list in it, in turn containing all elements), replace the last 2 lines with:

    if start:
        slices.append(lst[start:])
        yield slices