Supposons que j'ai une liste k = [[1,1,1], [2,2], [3], [4]] , avec une limite de taille c = 4 .
Ensuite, j'aimerais trouver toutes les partitions possibles du sujet k ot c . Idéalement, le résultat devrait être:
[{[[1,1,1], [3]], [[2,2], [4]]}, {[[1 , 1,1], [4]], [[2,2], [3]]}, {[[1,1,1]], [[2,2], [3], [4]] }, ..., {[[1,1,1]], [[2,2]], [[3]], [[4]]}]
où J'ai utilisé la notation définie {} dans l'exemple ci-dessus (le cas réel est [] ) pour préciser ce qu'est une partition, où chaque partition contient des groupes de listes groupées ensemble.
J'ai implémenté l'algorithme suivant mais mes résultats ne correspondent pas:
def num_item(l):
flat_l = [item for sublist in l for item in sublist]
return len(flat_l)
def get_all_possible_partitions(lst, c):
p_opt = []
for l in lst:
p_temp = [l]
lst_copy = lst.copy()
lst_copy.remove(l)
iterations = 0
while num_item(p_temp) <= c and iterations <= len(lst_copy):
for l_ in lst_copy:
iterations += 1
if num_item(p_temp + [l_]) <= c:
p_temp += [l_]
p_opt += [p_temp]
return p_opt
Exécution de get_all_possible_partitions (k, 4) , J'obtiens:
[[[1, 1, 1], [3]], [[2, 2], [3], [4]], [[3], [1, 1, 1]], [[4], [1, 1, 1]]]
Je comprends que cela ne supprime pas les doublons et n'épuise pas les combinaisons possibles, ce que je Je suis coincé.
Certaines informations seront formidables! P.S. Je n'ai pas réussi à trouver des questions similaires: /
3 Réponses :
Si tous les éléments de la liste sont uniques, vous pouvez utiliser bit.
Supposons que k = [a, b, c], dont la longueur est 3, alors il y a 2 ^ 3 - 1 = 7 partions:
si vous utilisez bit pour représenter a, b, c, il y aura
001 -> [c] 010 -> [b] 011 -> [b, c] 100 -> [a] 101 -> [a,c] 110 -> [a,b] 111 -> [a,b,c]
donc, la clé pour résoudre cette question est maintenant évidente. p>
Je pense que cela fait ce que vous voulez (explications dans les commentaires):
(([1, 1, 1],), ([2, 2],), ([3],), ([4],)) (([1, 1, 1],), ([2, 2],), ([3], [4])) (([1, 1, 1],), ([2, 2], [3]), ([4],)) (([1, 1, 1],), ([2, 2], [3], [4])) (([1, 1, 1],), ([2, 2], [4]), ([3],)) (([1, 1, 1], [3]), ([2, 2],), ([4],)) (([1, 1, 1], [3]), ([2, 2], [4])) (([1, 1, 1], [4]), ([2, 2],), ([3],)) (([1, 1, 1], [4]), ([2, 2], [3]))
Sortie:
# Main function
def get_all_possible_partitions(lst, c):
yield from _get_all_possible_partitions_rec(lst, c, [False] * len(lst), [])
# Produces partitions recursively
def _get_all_possible_partitions_rec(lst, c, picked, partition):
# If all elements have been picked it is a complete partition
if all(picked):
yield tuple(partition)
else:
# Get all possible subsets of unpicked elements
for subset in _get_all_possible_subsets_rec(lst, c, picked, [], 0):
# Add the subset to the partition
partition.append(subset)
# Generate all partitions that complete the current one
yield from _get_all_possible_partitions_rec(lst, c, picked, partition)
# Remove the subset from the partition
partition.pop()
# Produces all possible subsets of unpicked elements
def _get_all_possible_subsets_rec(lst, c, picked, current, idx):
# If we have gone over all elements finish
if idx >= len(lst): return
# If the current element is available and fits in the subset
if not picked[idx] and len(lst[idx]) <= c:
# Mark it as picked
picked[idx] = True
# Add it to the subset
current.append(lst[idx])
# Generate the subset
yield tuple(current)
# Generate all possible subsets extending this one
yield from _get_all_possible_subsets_rec(lst, c - len(lst[idx]), picked, current, idx + 1)
# Remove current element
current.pop()
# Unmark as picked
picked[idx] = False
# Only allow skip if it is not the first available element
if len(current) > 0 or picked[idx]:
# Get all subsets resulting from skipping current element
yield from _get_all_possible_subsets_rec(lst, c, picked, current, idx + 1)
# Test
k = [[1, 1, 1], [2, 2], [3], [4]]
c = 4
partitions = list(get_all_possible_partitions(k, c))
print(*partitions, sep='\n')
Oui c'est ce dont j'ai besoin! Merci beaucoup pour l'aide :)
Remarque : Cette réponse est en fait pour un question liée fermée .
Si vous souhaitez uniquement renvoyer les bipartitions de la liste, vous pouvez utiliser more_iterools. set_partions :
>>> from more_itertools import set_partitions >>> >>> def get_bipartions(lst): ... half_list_len = len(lst) // 2 ... if len(lst) % 2 == 0: ... return list( ... map(tuple, [ ... p ... for p in set_partitions(lst, k=2) ... if half_list_len == len(p[0]) ... ])) ... else: ... return list( ... map(tuple, [ ... p ... for p in set_partitions(lst, k=2) ... if abs(half_list_len - len(p[0])) < 1 ... ])) ... >>> get_bipartions(['A', 'B', 'C']) [(['A'], ['B', 'C']), (['B'], ['A', 'C'])] >>> get_bipartions(['A', 'B', 'C', 'D']) [(['A', 'B'], ['C', 'D']), (['B', 'C'], ['A', 'D']), (['A', 'C'], ['B', 'D'])] >>> get_bipartions(['A', 'B', 'C', 'D', 'E']) [(['A', 'B'], ['C', 'D', 'E']), (['B', 'C'], ['A', 'D', 'E']), (['A', 'C'], ['B', 'D', 'E']), (['C', 'D'], ['A', 'B', 'E']), (['B', 'D'], ['A', 'C', 'E']), (['A', 'D'], ['B', 'C', 'E'])]