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'])]