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.

34
demandé sur martineau 2011-12-04 03:28:42

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]]
43
répondu Óscar López 2017-10-06 13:27:40

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.

8
répondu Arel 2015-07-17 11:14:14

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 1len(l)).

en savoir Plus sur les combinaisons: http://docs.python.org/library/itertools.html#itertools.combinations

6
répondu juliomalegria 2011-12-03 23:40:12

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)
5
répondu Andrew Clark 2011-12-03 23:48:20
l = [1,2,3]
combs = reduce(lambda x, y: list(itertools.combinations(l, y)) + x, range(len(l)+1), [])

Si vous voulez un oneliner.

1
répondu Prafulla Mahesh Pallal 2017-12-10 19:13:30