EDIT
Based upon OP's new input/output requirements, it's just a couple of lines:
def groupings(lst, min_size):
results = [tuple(lst)]
for i in range(min_size, len(lst)):
results.extend(combinations(lst, i))
return results
ORIGINAL
(Based on an incorrect assumption that OP wanted all possible partitions given a minimum partition size.)
So itertools.combinations() should be a starting point. For example,
>>> list(combinations('ABCD', 2))
[('A', 'B'), ('A', 'C'), ('A', 'D'), ('B', 'C'), ('B', 'D'), ('C', 'D')]
So that gives one piece of your answer. The output of your grouping for 'ABCD' with min size set to 2 is:
[['A', 'B', 'C', 'D']]
[['A', 'D'], ['B', 'C']]
[['A', 'C'], ['B', 'D']]
[['A', 'B'], ['C', 'D']]
So the high-level process should be roughly:
results = []
remaining = [([], list)] # Start without any groups and the full list
while remaining not empty:
groups, list = remaining.pop()
if len(list) >= min_size:
results.append(groups + list)
for size in min_size to len(list) - 1:
for combo in combinations:
new <- (groups + combo, list - combo)
if new will not cause duplicates:
remaining.append(new)
Here is some code that seems to work. To avoid duplicates, and handle the cases where the original list might have duplicates, I modified the code from itertools.combinations, rather than just using the method.
def groupings(lst, min_size):
lst = list(lst)
# List for storing our final groupings
results = []
# Unfinished grouping, tuple storing the group and remaining sub-list
# Initialize with the empty group and original list
remaining = [([], lst)]
# Continue as long as we have unfinished groupings
while len(remaining):
# Get an unfinished grouping
current_group, current_lst = remaining.pop()
n = len(current_lst)
# If the last part of the list is big enough,
# then record the grouping
if n >= min_size:
results.append(current_group + [current_lst])
# Otherwise, discard it
else:
continue
# Helper set for getting remainder below
all_indices = set(range(n))
# Iterate the group length from min_size to the length of our current list
for r in range(min_size, n - 1):
# This is a modified version of itertools.combinations()
# http://docs.python.org/3.3/library/itertools.html#itertools.combinations
# Add the first combination to our remaining list
indices = list(range(r))
remainder = current_lst[r:]
group = current_group + [current_lst[:r]]
remaining.append((group, remainder))
while True:
for i in reversed(range(r)):
if indices[i] != i + n - r:
break
else:
break
indices[i] += 1
for j in range(i+1, r):
indices[j] = indices[j-1] + 1
# If one of the remaining indexes is less than the minimum used index,
# then a different iteration will handle it, so discard this one
min_index = min(indices)
remainder = []
for i in all_indices.difference(indices):
remainder.append(current_lst[i])
if i < min_index:
break
else:
# Add this combination to our remaining list
group = current_group + [[current_lst[i] for i in indices]]
remaining.append((group, remainder))
return results
The results:
>>> groupings('ABCDE', 2)
[['A', 'B', 'C', 'D', 'E']]
[['A', 'D', 'E'], ['B', 'C']]
[['A', 'C', 'E'], ['B', 'D']]
[['A', 'C', 'D'], ['B', 'E']]
[['A', 'B', 'E'], ['C', 'D']]
[['A', 'B', 'D'], ['C', 'E']]
[['A', 'B', 'C'], ['D', 'E']]
[['A', 'E'], ['B', 'C', 'D']]
[['A', 'D'], ['B', 'C', 'E']]
[['A', 'C'], ['B', 'D', 'E']]
[['A', 'B'], ['C', 'D', 'E']]