J'ai besoin de pouvoir faire une liste qui contient toutes les combinaisons possibles d'une liste entrée. Par exemple, la liste [1,2,3]
devrait renvoyer [1 [1,2] [1,3] 2 [2,3] 3 [1,2,3]]
La liste ne doit pas être dans un ordre particulier. Sur ce site, j'ai trouvé beaucoup de fonctions utilisant le itertools
mais celles-ci retournent des objets quand j'ai besoin juste d'un list
.
Utilisez simplement itertools.combinations
. Par exemple:
import itertools
lst = [1, 2, 3]
combs = []
for i in xrange(1, len(lst)+1):
combs.append(i)
els = [list(x) for x in itertools.combinations(lst, i)]
combs.append(els)
Maintenant, combs
contient cette valeur:
[1, [[1], [2], [3]], 2, [[1, 2], [1, 3], [2, 3]], 3, [[1, 2, 3]]]
Oui, il est légèrement différent de l'exemple de sortie que vous avez fourni, mais dans cette sortie, vous ne répertoriez pas toutes les combinaisons possibles.
Je liste la taille de la combinaison avant la liste réelle de chaque taille, si ce dont vous avez besoin est simplement les combinaisons (sans la taille, car elle apparaît dans votre exemple de sortie), puis essayez ces autres versions du code:
import itertools
lst = [1, 2, 3]
combs = []
for i in xrange(1, len(lst)+1):
els = [list(x) for x in itertools.combinations(lst, i)]
combs.extend(els)
Maintenant, combs
contient cette valeur:
[[1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]]
Le module itertools
renvoie en effet générateurs au lieu de listes, mais:
list(...)
quand vous en avez vraiment besoin.Les fonctions chain
et combinations
de itertools
fonctionnent bien, mais vous devez utiliser Python 2.6 ou supérieur :
import itertools
def all_combinations(any_list):
return itertools.chain.from_iterable(
itertools.combinations(any_list, i + 1)
for i in xrange(len(any_list)))
Vous pouvez alors appeler cela comme tel:
# as a generator
all_combinations([1,2,3]) # --> <itertools.chain at 0x10ef7ce10>
# as a list
list(all_combinations([1,2,3])) # --> [(1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]
# as a list of lists
[list(l) for l in all_combinations([1,2,3])] # --> [[1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]]
Si vous n'avez jamais utilisé de générateurs auparavant, notez que vous les parcourez comme s'ils étaient une liste, comme celle-ci:
# a generator returned instead of list
my_combinations = all_combinations([1,2,3])
# this would also work if `my_combinations` were a list
for c in my_combinations:
print "Combo", c
"""
Prints:
Combo (1,)
Combo (2,)
Combo (3,)
Combo (1, 2)
Combo (1, 3)
Combo (2, 3)
Combo (1, 2, 3)
"""
La différence de performances peut être dramatique. Si vous comparez les performances, vous verrez que le générateur est beaucoup plus rapide à créer:
# as a generator
all_combinations(range(25)) # timing: 100000 loops, best of 3: 2.53 µs per loop
# as a list
list(all_combinations(range(25))) # timing: 1 loops, best of 3: 9.37 s per loop
Notez qu'il faudrait encore un certain temps pour parcourir toutes les combinaisons dans les deux cas, mais cela peut être une grande victoire pour vous, surtout si vous trouvez ce que vous recherchez au début.
Les fonctions du module itertools renvoient des itérateurs. Tout ce que vous devez faire pour les convertir en listes est d'appeler list()
sur le résultat.
Cependant, puisque vous devrez appeler itertools.combinations
trois fois distinctes (une fois pour chaque longueur différente), vous pouvez simplement utiliser list.extend
pour ajouter tous les éléments de l'itérateur à votre liste finale.
Essayez ce qui suit:
import itertools
in_list = [1, 2, 3]
out_list = []
for i in range(1, len(in_list)+1):
out_list.extend(itertools.combinations(in_list, i))
Ou comme compréhension de liste:
out_list = [c for i in range(len(in_list)) for c in itertools.combinations(in_list, i+1)]
Il en résultera la liste suivante:
[(1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]
Si vous voulez des listes au lieu de tuples, et pour convertir les tuples de longueur unique en juste la valeur, vous pouvez faire ce qui suit:
out_list = [x[0] if len(x) == 1 else list(x) for x in out_list]
# [1, 2, 3, [1, 2], [1, 3], [2, 3], [1, 2, 3]]
Ou pour laisser les éléments individuels sous forme de listes:
out_list = map(list, out_list)
Vous pouvez résoudre votre problème en utilisant itertools.combinations
À l'intérieur d'une boucle:
>>> l = [1,2,3]
>>> comb = []
>>> for i in range(len(l)):
... comb += itertools.combinations(l,i+1)
...
>>> comb
[(1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]
Et si vous les voulez comme liste:
>>> comb_list = [ list(t) for t in comb ]
>>> comb_list
[[1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]]
EDIT: Le premier paramètre des combinaisons est l'itérable et le second est la longueur des tuples résultants (dans ce cas, en passant de 1
à len(l)
).
En savoir plus sur les combinaisons: http://docs.python.org/library/itertools.html#itertools.combinations
l = [1,2,3]
combs = reduce(lambda x, y: list(itertools.combinations(l, y)) + x, range(len(l)+1), [])
Si vous voulez un oneliner.
Je pense que cela vaut la peine de résumer les autres réponses ici dans un simple Python 3 exemple:
from itertools import chain, combinations
def all_combinations(array):
return chain(*(list(combinations(array, i + 1)) for i in range(len(array))))
Cela renvoie un itérable, pour afficher les valeurs:
>>> print(list(all_combinations((1, 2, 3))))
[(1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]