问题
I have a list of unique elements, let's say [1,2], and I want to split it onto k=2 sublists. Now I want to have all possible sublists:
[ [ [1,2],[] ], [ [1],[2] ], [ [2],[1] ], [ [],[1,2] ] ]
And I want to split onto 1<=k<=n sublists, so for k=1 it will be:
[ [1, 2] ]
How can I do that with Python 3?
UPDATE: my goal is to get all possible partitions of list of N unique numbers, where each partition will have k sublists. I would like to show better example than I have shown upper, I hope I will not miss something. So for list [1, 2, 3] and for k=2 I want to have next list:
[
[ [1,2,3], [] ],
[ [2,3], [1] ],
[ [1,3], [2] ],
[ [1,2], [3] ],
[ [1], [2,3] ],
[ [2], [1,3] ],
[ [3], [2,3] ],
[ [], [1,2,3] ]
]
UPDATE 2: so far I have combined two suggestions and little modification got next code:
def sorted_k_partitions(seq, k):
"""Returns a list of all unique k-partitions of `seq`.
Each partition is a list of parts, and each part is a tuple.
The parts in each individual partition will be sorted in shortlex
order (i.e., by length first, then lexicographically).
The overall list of partitions will then be sorted by the length
of their first part, the length of their second part, ...,
the length of their last part, and then lexicographically.
"""
n = len(seq)
groups = [] # a list of lists, currently empty
def generate_partitions(i):
if i >= n:
yield list(map(tuple, groups))
else:
if n - i > k - len(groups):
for group in groups:
group.append(seq[i])
yield from generate_partitions(i + 1)
group.pop()
if len(groups) < k:
groups.append([seq[i]])
yield from generate_partitions(i + 1)
groups.pop()
result = generate_partitions(0)
# Sort the parts in each partition in shortlex order
result = [sorted(ps, key = lambda p: (len(p), p)) for ps in result]
# Sort partitions by the length of each part, then lexicographically.
result = sorted(result, key = lambda ps: (*map(len, ps), ps))
return result
With this function I can do next:
import itertools as it
k=2
S = [1, 2, 3]
for i in (range(k)):
for groups in sorted_k_partitions(S, k-i):
for perm in it.permutations(groups+[tuple() for j in range(i)]):
print(perm)
The output is:
((1,), (2, 3))
((2, 3), (1,))
((2,), (1, 3))
((1, 3), (2,))
((3,), (1, 2))
((1, 2), (3,))
((1, 2, 3), ())
((), (1, 2, 3))
I'm not sure yet, that this code gives me right solution, maybe there is other way?
回答1:
Here is an alternative solution:
def partition_k(l, k):
n = len(l)
if k > n:
raise ValueError("k = {0} should be no more than n = {1}".format(k, n))
if n == 0:
yield []
return
pos = [0] * n
while True:
# generate output for the value
out = [[] for _ in range(k)]
for i in range(n):
out[pos[i]].append(l[i])
yield out
#increment the value
pos[0] += 1
for i in range(n):
# should we carry from this digit to the next one?
if pos[i] == k:
# overflow of the whole value?
if i == n - 1:
return
pos[i] = 0
pos[i + 1] += 1
else:
break
Let n be the length of the list and k is the number of partitions. The idea behind this code is that each line of the output can be represented as a number of n digits in base-k system. Each "digit" shows in which bucket goes the value at corresponding position. For example line
[[2,3], [1], [4]]
can be encoded as [1,0,0,2] which means
1goes to the bucket #12goes to the bucket #03goes to the bucket #04goes to the bucket #2
Obviously every such n-digits base-k number represents a valid partition of the list and each partition is represented by some number. So to generate all partitions we need just iterate through all such numbers and generate corresponding partitions. It is easier to do if you use a list of digits to represent a number (in the code this is pos).
来源:https://stackoverflow.com/questions/53937159/how-to-find-all-partitions-of-a-list-s-into-k-subsets-can-be-empty