299 votes

Toutes les combinaisons d'une liste de listes

Je suis essentiellement à la recherche d'une version python de Combinaison de List<List<int>>

Étant donné une liste de listes, j'ai besoin d'une nouvelle liste qui donne toutes les combinaisons possibles d'éléments entre les listes.

[[1,2,3],[4,5,6],[7,8,9,10]] -> [[1,4,7],[1,4,8],...,[3,6,10]]

Le nombre de listes est inconnu, j'ai donc besoin de quelque chose qui fonctionne pour tous les cas. Des points bonus pour l'élégance !

4voto

rnso Points 11304

On peut utiliser la base python pour cela. Le code a besoin d'une fonction pour aplatir des listes de listes :

def flatten(B):    # function needed for code below;
    A = []
    for i in B:
        if type(i) == list: A.extend(i)
        else: A.append(i)
    return A

Alors on peut courir :

L = [[1,2,3],[4,5,6],[7,8,9,10]]

outlist =[]; templist =[[]]
for sublist in L:
    outlist = templist; templist = [[]]
    for sitem in sublist:
        for oitem in outlist:
            newitem = [oitem]
            if newitem == [[]]: newitem = [sitem]
            else: newitem = [newitem[0], sitem]
            templist.append(flatten(newitem))

outlist = list(filter(lambda x: len(x)==len(L), templist))  # remove some partial lists that also creep in;
print(outlist)

Sortie :

[[1, 4, 7], [2, 4, 7], [3, 4, 7], 
[1, 5, 7], [2, 5, 7], [3, 5, 7], 
[1, 6, 7], [2, 6, 7], [3, 6, 7], 
[1, 4, 8], [2, 4, 8], [3, 4, 8], 
[1, 5, 8], [2, 5, 8], [3, 5, 8], 
[1, 6, 8], [2, 6, 8], [3, 6, 8], 
[1, 4, 9], [2, 4, 9], [3, 4, 9], 
[1, 5, 9], [2, 5, 9], [3, 5, 9], 
[1, 6, 9], [2, 6, 9], [3, 6, 9], 
[1, 4, 10], [2, 4, 10], [3, 4, 10], 
[1, 5, 10], [2, 5, 10], [3, 5, 10], 
[1, 6, 10], [2, 6, 10], [3, 6, 10]]

0voto

cellepo Points 124

Cela ressemble surtout à des solutions comme Réponse de Jarret Hardie en utilisant itertools.product mais avec ces distinctions :

  • ce qui permet de passer des paramètres à itertools.product en ligne, plutôt que via la variable a - alors non *args syntaxe nécessaire sur les paramètres en ligne
  • si votre mypy type-linter se comporte comme le mien, et vous pouvez faire en sorte que votre code "fonctionne" autrement avec l'option *args avec la syntaxe en ligne product (comme product(*[[1,2,3],[4,5,6],[7,8,9,10]]) ), mypy pourrait encore échouer (avec quelque chose comme error: No overload variant of "product" matches argument type "List[object]" )
  • Donc, la solution à ce problème mypy est de ne pas utiliser *args syntaxe, comme ceci :

    >>> import itertools
    >>> list(itertools.product([1,2,3],[4,5,6],[7,8,9,10]))
    [(1, 4, 7), (1, 4, 8), (1, 4, 9), (1, 4, 10), (1, 5, 7), (1, 5, 8), (1, 5, 9), (1, 5, 10), (1, 6, 7), (1, 6, 8), (1, 6, 9), (1, 6, 10), (2, 4, 7), (2, 4, 8), (2, 4, 9), (2, 4, 10), (2, 5, 7), (2, 5, 8), (2, 5, 9), (2, 5, 10), (2, 6, 7), (2, 6, 8), (2, 6, 9), (2, 6, 10), (3, 4, 7), (3, 4, 8), (3, 4, 9), (3, 4, 10), (3, 5, 7), (3, 5, 8), (3, 5, 9), (3, 5, 10), (3, 6, 7), (3, 6, 8), (3, 6, 9), (3, 6, 10)]

0voto

Kweku A Points 1

Cette réponse n'est pas aussi propre que l'utilisation de itertools mais les idées peuvent être utiles.

En s'inspirant de la construction de zip() aquí nous pourrions faire ce qui suit.

>>> a = iter([[1,2,3],[4,5,6],[7,8,9,10]])
>>> sentinel = object()
>>> result = [[]]
>>> while True:
>>>     l = next(a,sentinel)
>>>     if l == sentinel:
>>>         break
>>>     result = [ r + [digit] for r in result for digit in l]
>>> print(result)
[[1, 4, 7], [1, 4, 8], [1, 4, 9], [1, 4, 10], [1, 5, 7], [1, 5, 8], [1, 5, 9], [1, 5, 10], [1, 6, 7], [1, 6, 8], [1, 6, 9], [1, 6, 10], [2, 4, 7], [2, 4, 8], [2, 4, 9], [2, 4, 10], [2, 5, 7], [2, 5, 8], [2, 5, 9], [2, 5, 10], [2, 6, 7], [2, 6, 8], [2, 6, 9], [2, 6, 10], [3, 4, 7], [3, 4, 8], [3, 4, 9], [3, 4, 10], [3, 5, 7], [3, 5, 8], [3, 5, 9], [3, 5, 10], [3, 6, 7], [3, 6, 8], [3, 6, 9], [3, 6, 10]]

Nous utilisons a comme un itérateur afin d'obtenir successivement le prochain élément de celui-ci sans avoir besoin de savoir combien il y en a a a priori. Le site next La commande produira sentinel (qui est un objet créé uniquement pour effectuer cette comparaison, voir aquí pour une explication) lorsque nous sommes à court de listes dans a Ce qui fait que le if à déclencher pour que nous sortions de la boucle.

1 votes

En effet, c'est plus ou moins ce que itertools.product fait, -- voir ici -- à l'exception de l'utilisation d'une sentinelle alors que itertools.product utilise yield .

-1voto

Kez Points 9
from itertools import product 
list_vals = [['Brand Acronym:CBIQ', 'Brand Acronym :KMEFIC'],['Brand Country:DXB','Brand Country:BH']]
list(product(*list_vals))

Sortie :

[('Brand Acronym:CBIQ', 'Brand Country :DXB'),
("Brand Acronym:CBIQ", "Brand Country:BH"),
('Brand Acronym :KMEFIC', 'Brand Country :DXB'),
('Acronyme de la marque :KMEFIC', 'Pays de la marque :BH')]

0 votes

Cette réponse devrait être acceptée, puisque c'est la seule qui utilise une fonction intégrée, tout en soulignant qu'elle fonctionne également pour tous les types et aussi pour les types hétérogènes.

4 votes

En quoi cette réponse est-elle différente de celle fournie il y a de nombreuses années ?

0 votes

Les types de paramètres sont ici homogènes, non hétrogènes.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X