combinaisons entre deux listes?

203

Cela fait un moment et j'ai du mal à comprendre un algorithme que j'essaie de créer. En gros, j'ai deux listes et je veux obtenir toutes les combinaisons des deux listes.

Je ne l'explique peut-être pas correctement, alors voici un exemple.

name = 'a', 'b'
number = 1, 2

la sortie dans ce cas serait:

1.  A1 B2
2.  B1 A2

La partie la plus délicate est que je pourrais avoir plus d'éléments dans la variable «nom» que d'éléments dans la variable «nombre» (le nombre sera toujours égal ou inférieur à la variable nom).

Je ne sais pas comment faire toutes les combinaisons (imbriquées pour la boucle?) Et encore plus confus sur la logique pour déplacer les éléments dans la variable de nom dans le cas où il y aurait plus d'éléments dans le nom qu'ils ne le sont dans la liste de numéros.

Je ne suis pas le meilleur programmeur, mais je pense que je peux essayer si quelqu'un peut m'aider à clarifier la logique / algorithme pour y parvenir. Je viens donc d'être bloqué sur des boucles for imbriquées.

Mise à jour:

Voici la sortie avec 3 variables et 2 nombres:

name = 'a', 'b', 'c'
number = 1, 2

production:

1.  A1 B2
2.  B1 A2
3.  A1 C2
4.  C1 A2
5.  B1 C2
6.  C1 B2
user1735075
la source
1
@ dm03514 J'ai vu cela, et j'ai trouvé des exemples pour des objectifs quelque peu similaires en utilisant itertools mais je fais un prototypage en python mais j'écrirai le code final dans un autre langage, donc je ne veux pas utiliser d'outils qui ne sont pas disponibles autrement.
user1735075
1
Ce que vous demandez n'a pas vraiment de sens. Si la première liste contient A, B, C et la seconde contient 1,2, quel résultat attendez-vous? Cela pourrait être fait si l'exemple que vous avez donné avait 4 résultats différents d'une lettre et un chiffre chacun (A1, A2, B1, B2), ou si les deux listes devaient avoir la même taille.
entre
1
Je suis d'accord avec Interjay. Veuillez spécifier le résultat dans le cas de taille non égale, sinon il n'est pas possible de fournir une solution générale.
Bakuriu
Salut tout le monde, j'ai mis à jour la réponse pour afficher la sortie avec 3 noms et 2 numéros .. Je pensais que je l'ai bien expliqué, je ne sais pas pourquoi le vote négatif.
user1735075

Réponses:

102

Remarque : Cette réponse concerne la question spécifique posée ci-dessus. Si vous êtes ici de Google et que vous cherchez simplement un moyen d'obtenir un produit cartésien en Python, itertools.productou une simple compréhension de liste peut être ce que vous recherchez - voir les autres réponses.


Supposons len(list1) >= len(list2). Alors ce que vous semblez vouloir est de prendre toutes les permutations de longueur len(list2)de list1et les jumeler avec des articles de liste2. En python:

import itertools
list1=['a','b','c']
list2=[1,2]

[list(zip(x,list2)) for x in itertools.permutations(list1,len(list2))]

Retour

[[('a', 1), ('b', 2)], [('a', 1), ('c', 2)], [('b', 1), ('a', 2)], [('b', 1), ('c', 2)], [('c', 1), ('a', 2)], [('c', 1), ('b', 2)]]
interjay
la source
2
Le résultat est exactement ce que je veux, mais est-il possible de partager la logique derrière la façon de le faire? Si je convertis mon code en C ou Java, je n'aurai pas accès à zip ou itertools (bien qu'ils rendent la vie très très facile)
user1735075
3
@ user1735075 Jetez un œil à la documentation
paresseux
1
@ user1735075: savez-vous que python est open source? Vous pouvez donc simplement télécharger les sources et voir ce qu'elles font. +1 à M. Steak pour avoir souligné que la documentation a en fait un exemple d'implémentation qui n'utilise pas zipet similaire.
Bakuriu
2
Je ne peux littéralement pas faire fonctionner cela, même avec votre exemple ... tout ce que j'obtiens est une liste d'objets zip ..: |
m1nkeh
1
@logic fournit ce qui devrait être la solution acceptée.
Bernhard Wagner le
535

Le moyen le plus simple est d'utiliser itertools.product:

a = ["foo", "melon"]
b = [True, False]
c = list(itertools.product(a, b))
>> [("foo", True), ("foo", False), ("melon", True), ("melon", False)]
DrIDK
la source
11
OP ne demandait pas de produit cartésien, et cette réponse (ainsi que la plupart des autres) ne donne pas le résultat attendu spécifié dans la question.
entre le
18
@interjay vous avez tout à fait raison, mais comme trop de gens semblent trouver cette réponse correcte, je ne peux que supposer que le titre de la question manque de contexte.
xpy
3
@xpy Le titre est trop court pour tout expliquer. C'est pourquoi vous devez lire la question réelle.
entre le
11
OP voulait des permulations, mais Google envoie à tous ceux qui recherchent des combinaisons (comme moi) cette réponse - heureux de voir qu'elle a obtenu 8 fois les votes!
Josh Friedlander
171

Peut être plus simple que le plus simple ci-dessus:

>>> a = ["foo", "bar"]
>>> b = [1, 2, 3]
>>> [(x,y) for x in a for y in b]  # for a list
[('foo', 1), ('foo', 2), ('foo', 3), ('bar', 1), ('bar', 2), ('bar', 3)]
>>> ((x,y) for x in a for y in b)  # for a generator if you worry about memory or time complexity.
<generator object <genexpr> at 0x1048de850>

sans aucune importation

logique
la source
Meilleure solution! Merci! D'autres solutions sont soit tout à fait erronées, soit ne fonctionnent que dans des cas spécifiques comme a> b etc.
Philipp Schwarz
3
La solution la plus pythonique! (et évite les importations inutiles)
Dalker
6
La complexité du temps est O (n ^ 2)
Deepak Sharma
2
Solution de paris !! Bare basics est la meilleure façon de toujours
Sabyasachi
24

Je cherchais une liste multipliée par elle-même avec uniquement des combinaisons uniques, qui est fournie comme cette fonction.

import itertools
itertools.combinations(list, n_times)

Voici un extrait de la documentation Python sur itertools Cela pourrait vous aider à trouver ce que vous cherchez.

Combinatoric generators:

Iterator                                 | Results
-----------------------------------------+----------------------------------------
product(p, q, ... [repeat=1])            | cartesian product, equivalent to a 
                                         |   nested for-loop
-----------------------------------------+----------------------------------------
permutations(p[, r])                     | r-length tuples, all possible 
                                         |   orderings, no repeated elements
-----------------------------------------+----------------------------------------
combinations(p, r)                       | r-length tuples, in sorted order, no 
                                         |   repeated elements
-----------------------------------------+----------------------------------------
combinations_with_replacement(p, r)      | r-length tuples, in sorted order, 
                                         | with repeated elements
-----------------------------------------+----------------------------------------
product('ABCD', repeat=2)                | AA AB AC AD BA BB BC BD CA CB CC CD DA DB DC DD
permutations('ABCD', 2)                  | AB AC AD BA BC BD CA CB CD DA DB DC
combinations('ABCD', 2)                  | AB AC AD BC BD CD
combinations_with_replacement('ABCD', 2) | AA AB AC AD BB BC BD CC CD DD
ThorSummoner
la source
11

Vous voudrez peut-être essayer une compréhension de liste en une ligne:

>>> [name+number for name in 'ab' for number in '12']
['a1', 'a2', 'b1', 'b2']
>>> [name+number for name in 'abc' for number in '12']
['a1', 'a2', 'b1', 'b2', 'c1', 'c2']
Idanmel
la source
11

la meilleure façon de découvrir toutes les combinaisons pour un grand nombre de listes est:

import itertools
from pprint import pprint

inputdata = [
    ['a', 'b', 'c'],
    ['d'],
    ['e', 'f'],
]
result = list(itertools.product(*inputdata))
pprint(result)

le résultat sera:

[('a', 'd', 'e'),
 ('a', 'd', 'f'),
 ('b', 'd', 'e'),
 ('b', 'd', 'f'),
 ('c', 'd', 'e'),
 ('c', 'd', 'f')]
Ishan Rastogi
la source
Merci, bonne réponse!
toinbis
10

Ou la réponse KISS pour les listes courtes:

[(i, j) for i in list1 for j in list2]

Pas aussi performant que itertools mais vous utilisez python donc les performances ne sont déjà pas votre principale préoccupation ...

J'aime aussi toutes les autres réponses!

Fletch F Fletch
la source
8

une petite amélioration pour la réponse de l'interjay, pour rendre le résultat comme une liste aplatie.

>>> list3 = [zip(x,list2) for x in itertools.permutations(list1,len(list2))]
>>> import itertools
>>> chain = itertools.chain(*list3)
>>> list4 = list(chain)
[('a', 1), ('b', 2), ('a', 1), ('c', 2), ('b', 1), ('a', 2), ('b', 1), ('c', 2), ('c', 1), ('a', 2), ('c', 1), ('b', 2)]

référence à partir de ce lien

Mass Zhou
la source
4

Sans itertools

[(list1[i], list2[j]) for i in xrange(len(list1)) for j in xrange(len(list2))]
user3684792
la source
4

En répondant à la question "étant donné deux listes, trouvez toutes les permutations possibles de paires d'un élément de chaque liste" et en utilisant les fonctionnalités de base de Python (c'est-à-dire sans itertools) et, par conséquent, en facilitant la réplication pour d'autres langages de programmation:

def rec(a, b, ll, size):
    ret = []
    for i,e in enumerate(a):
        for j,f in enumerate(b):
            l = [e+f]
            new_l = rec(a[i+1:], b[:j]+b[j+1:], ll, size)
            if not new_l:
                ret.append(l)
            for k in new_l:
                l_k = l + k
                ret.append(l_k)
                if len(l_k) == size:
                    ll.append(l_k)
    return ret

a = ['a','b','c']
b = ['1','2']
ll = []
rec(a,b,ll, min(len(a),len(b)))
print(ll)

Retour

[['a1', 'b2'], ['a1', 'c2'], ['a2', 'b1'], ['a2', 'c1'], ['b1', 'c2'], ['b2', 'c1']]
informaticien
la source
4

Les meilleures réponses à cela ne fonctionnent que pour des longueurs spécifiques de listes fournies.

Voici une version qui fonctionne pour toutes les longueurs d'entrée. Cela rend également l'algorithme clair en termes de concepts mathématiques de combinaison et de permutation.

from itertools import combinations, permutations
list1 = ['1', '2']
list2 = ['A', 'B', 'C']

num_elements = min(len(list1), len(list2))
list1_combs = list(combinations(list1, num_elements))
list2_perms = list(permutations(list2, num_elements))
result = [
  tuple(zip(perm, comb))
  for comb in list1_combs
  for perm in list2_perms
]

for idx, ((l11, l12), (l21, l22)) in enumerate(result):
  print(f'{idx}: {l11}{l12} {l21}{l22}')

Cela produit:

0: A1 B2
1: A1 C2
2: B1 A2
3: B1 C2
4: C1 A2
5: C1 B2
Steve Alexander
la source