This follows on from this question:
Algorithm to generate spanning set
Given this input: [1,2,3,4]
I\'d like to generate this set of sets in python:<
Adjusting one of the solution from Python: show all possible groupings of a list:
from itertools import combinations
def cut(lst, indexes):
last = 0
for i in indexes:
yield lst[last:i]
last = i
yield lst[last:]
def generate(lst, n):
for indexes in combinations(list(range(1,len(lst))), n - 1):
yield list(cut(lst, indexes))
data = [1,2,3,4]
for i in range(1, len(data)+1): # the only difference is here
for g in generate(data, i):
print(g)
"""
[[1, 2, 3, 4]]
[[1], [2, 3, 4]]
[[1, 2], [3, 4]]
[[1, 2, 3], [4]]
[[1], [2], [3, 4]]
[[1], [2, 3], [4]]
[[1, 2], [3], [4]]
[[1], [2], [3], [4]]
"""
You might also enjoy a recursive solution:
def span(lst):
yield [lst]
for i in range(1, len(lst)):
for x in span(lst[i:]):
yield [lst[:i]] + x
We exploit recursion here to break the problem down. The approach is the following:
For every list, the whole list is a valid spanning: [1,2,3,4] => [[1,2,3,4]]
.
For every list that is longer than size 1
, we can use the first item as a group and then apply the same algorithm on the remaining list to get all the combined results:
[1,2,3] =>
[[1]] + [[2], [3]] # => [[1], [2], [3]]
[[1]] + [[2,3]] # => [[1], [2,3]]
For every list that is longer than size 2
, we can just as well use the first two items as a group and then apply the same algorithm on the remaining list and combine the results:
[1,2,3,4,5] =>
[[1,2]] + [[3], [4], [5]] # => [[1,2], [3], [4], [5]]
[[1,2]] + [[3,4], [5]] # => [[1,2], [3,4], [5]]
[[1,2]] + [[3], [4,5]] # => [[1,2], [3], [4,5]]
[[1,2]] + [[3,4,5]] # => [[1,2], [3,4,5]]
We can see that the possible combinations on the right side are indeed all possible groupings of the remainder of the list, [3,4,5]
.
For every list that is longer than ... etc. Thus, the final algorithm is the following:
yield
is a special keyword in Python that make the function a generator, which means that it returns a iterable object that can be used to enumerate all results found. You can transform the result into a list using the list
constructor function: list(span([1,2,3,4]))
.
import itertools
a = [1, 2, 3, 4]
n = len(a)
for num_splits in range(n):
for splits in itertools.combinations(range(1, n), num_splits):
splices = zip([0] + list(splits), list(splits) + [n])
print([a[i:j] for i, j in splices])
prints
[[1, 2, 3, 4]]
[[1], [2, 3, 4]]
[[1, 2], [3, 4]]
[[1, 2, 3], [4]]
[[1], [2], [3, 4]]
[[1], [2, 3], [4]]
[[1, 2], [3], [4]]
[[1], [2], [3], [4]]