Faire toutes les combinaisons possibles d'une liste
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 revenir [1 [1,2] [1,3] 2 [2,3] 3 [1,2,3]]
La liste n'a pas à être dans un ordre particulier. Sur ce site j'ai trouvé beaucoup de fonctions en utilisant le itertools
mais ce sont des objets qui reviennent quand j'ai juste besoin d'un list
.
5 réponses
il suffit d'utiliser 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)
combs
contient cette valeur:
[1, [[1], [2], [3]], 2, [[1, 2], [1, 3], [2, 3]], 3, [[1, 2, 3]]]
Oui, c'est légèrement différent de la sortie de l'échantillon que vous avez fourni, mais dans cette sortie vous ne listiez pas toutes les combinaisons possibles.
j'indique la taille de la combinaison avant la liste réelle pour chaque taille, si ce dont vous avez besoin est simplement les combinaisons (sans la taille, comme elle apparaît dans votre sortie d'échantillon) alors essayez cette autre version 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)
combs
contient cette valeur:
[[1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]]
itertools
le module retourne en effet générateurs au lieu de listes, mais:
- les générateurs sont souvent plus efficaces que les listes (surtout si vous générez un grand nombre de combinaisons)
- vous pouvez toujours convertir des générateurs en listes en utilisant
list(...)
lorsque vous en avez vraiment besoin.
chain
et combinations
fonctions itertools
fonctionne bien, mais vous devez utiliser Python 2.6 ou plus:
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 ensuite 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 pas utilisé des générateurs avant, notez que vous parcourez, comme si elles étaient d'une liste, comme ceci:
# 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 performance peut être dramatique. Si vous comparez la performance, 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 itérer toutes les combinaisons dans les deux cas, mais il peut être une grande victoire pour vous surtout si vous trouvez ce que vous cherchez tôt.
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 voulez la 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 de combinaisons est l'itérable et le second est la longueur des tuples résultants (dans ce cas, en allant de 1
len(l)
).
en savoir Plus sur les combinaisons: http://docs.python.org/library/itertools.html#itertools.combinations
les fonctions des itérateurs de retour du module itertools. Tout ce que vous devez faire pour convertir ces listes est call list()
sur le résultat.
Toutefois, puisque vous aurez besoin de faire appel itertools.combinations
trois fois (une fois pour chaque longueur), vous pouvez utiliser list.extend
pour ajouter tous les éléments de l'itérateur à votre liste finale.
Essayez la procédure suivante:
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 une compréhension de liste:
out_list = [c for i in range(len(in_list)) for c in itertools.combinations(in_list, i+1)]
Ces entraînera l' liste suivante:
[(1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]
si vous voulez des listes à la place des tuples, et pour convertir les tuples de longueur simple 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 à laisser, les éléments uniques comme des listes:
out_list = map(list, out_list)
l = [1,2,3]
combs = reduce(lambda x, y: list(itertools.combinations(l, y)) + x, range(len(l)+1), [])
Si vous voulez un oneliner.