¿Cómo puedo unir permutaciones de una lista larga con una lista más corta (según la longitud de la lista más corta)? [duplicate]

7 minutos de lectura

avatar de usuario de user1735075
usuario1735075

Tengo problemas para entender un algoritmo que estoy tratando de implementar. Tengo dos listas y quiero tomar combinaciones particulares de las dos listas.

Aquí hay un ejemplo.

names = ['a', 'b']
numbers = [1, 2]

la salida en este caso sería:

[('a', 1), ('b', 2)]
[('b', 1), ('a', 2)]

Podría tener más nombres que números, es decir len(names) >= len(numbers). Aquí hay un ejemplo con 3 nombres y 2 números:

names = ['a', 'b', 'c']
numbers = [1, 2]

producción:

[('a', 1), ('b', 2)]
[('b', 1), ('a', 2)]
[('a', 1), ('c', 2)]
[('c', 1), ('a', 2)]
[('b', 1), ('c', 2)]
[('c', 1), ('b', 2)]

  • docs.python.org/library/itertools.html

    – dm03514

    17 de octubre de 2012 a las 13:18

  • @ dm03514 Vi eso y encontré ejemplos para objetivos algo similares usando itertools pero estoy creando prototipos en python pero escribiré el código final en otro idioma, así que no quiero usar ninguna herramienta que no esté disponible de otra manera.

    – usuario1735075

    17 de octubre de 2012 a las 13:19

  • Lo que pides no tiene mucho sentido. Si la primera lista contiene A,B,C y la segunda contiene 1,2, ¿qué resultado esperaría? Se podría hacer si el ejemplo que diste tuviera 4 resultados diferentes de una letra y un número cada uno (A1, A2, B1, B2), o si ambas listas tuvieran que tener el mismo tamaño.

    – interjay

    17 de octubre de 2012 a las 13:24


  • Estoy de acuerdo con interjay. Especifique el resultado en el caso de tamaño diferente; de ​​lo contrario, no es posible proporcionar una solución general.

    – Bakuriu

    17/10/2012 a las 13:25

  • Nota para futuras personas que hagan preguntas dobles a esta: ¿Existe una posibilidad decente de obtener el producto cartesiano de una serie de listas? es un mejor objetivo duplicado (muchas cosas que deberían usar product se está duplicando aquí, aunque esta pregunta no se resuelve adecuadamente de esa manera). En casos más raros, ¿Todos los reemplazos posibles de dos listas? puede ser mejor (al seleccionar un valor de una de las dos listas en cada índice, que es un product solución de nuevo, con un zip paso previo).

    – ShadowRanger

    5 de marzo de 2019 a las 19:16

Avatar de usuario de DrIDK
DrIDK

La forma más sencilla es usar itertools.product:

a = ["foo", "melon"]
b = [True, False]
c = list(itertools.product(a, b))
>> [("foo", True), ("foo", False), ("melon", True), ("melon", False)]

  • OP no estaba pidiendo un producto cartesiano, y esta respuesta (así como la mayoría de las otras) no da el resultado esperado especificado en la pregunta.

    – interjay

    18 de julio de 2017 a las 14:49


  • @interjay tiene mucha razón, pero como muchas personas parecen encontrar esta respuesta correcta, solo puedo suponer que el título de la pregunta carece de contexto.

    – xpy

    20 de julio de 2017 a las 9:11

  • @xpy El título es demasiado corto para explicarlo todo. Es por eso que necesita leer la pregunta real.

    – interjay

    20 de julio de 2017 a las 9:18

  • OP quería permutaciones, pero Google envía a cualquiera que busque combinaciones (como yo) a esta respuesta. ¡Me alegra ver que tiene 8 veces más votos!

    –Josh Friedlander

    24 de diciembre de 2018 a las 15:38

  • @JoshFriedlander la mayoría de las personas que solicitan cualquiera de estas cosas no entienden la terminología; por lo tanto, hay toneladas de preguntas que utilizan una terminología incorrecta. Incluso si cerramos los duplicados agresivamente y nos aseguramos de que todo apunte al duplicado correcto para el problema de OP, aún así terminaremos con direcciones erróneas de búsqueda.

    – Karl Knechtel

    2 de marzo a las 0:35

avatar de usuario de lógica
lógica

Puede ser más simple que el más simple de arriba:

>>> 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>

sin ninguna importación

  • ¡Mejor solución! ¡Gracias! Otras soluciones son simplemente incorrectas o solo funcionan en casos específicos como a> b, etc.

    – Philipp Schwarz

    16 de febrero de 2018 a las 10:09

  • ¡La solución más pitónica! (y evita importaciones innecesarias)

    – Daker

    4 de agosto de 2018 a las 9:40

  • La complejidad del tiempo es O(n^2)

    – Deepak Sharma

    26 de enero de 2019 a las 18:41

  • Solución de apuestas!! Lo básico es la mejor manera siempre

    – Sabyasachi

    23 de febrero de 2019 a las 16:50

  • Claro, la complejidad del tiempo es n ^ 2, pero seguramente esto es completamente inevitable.

    – Mattwmaster58

    12 de marzo de 2022 a las 1:15

avatar de usuario de interjay
interjay

Nota: Esta respuesta es para la pregunta específica formulada anteriormente. Si está aquí desde Google y solo está buscando una manera de obtener un producto cartesiano en Python, itertools.product o una lista simple de comprensión puede ser lo que está buscando; vea las otras respuestas.


Suponer len(list1) >= len(list2). Entonces lo que parece querer es tomar todas las permutaciones de longitud len(list2) de list1 y combínalos con elementos de list2. En pitón:

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

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

Devoluciones

[[('a', 1), ('b', 2)], [('a', 1), ('c', 2)], [('b', 1), ('a', 2)], [('b', 1), ('c', 2)], [('c', 1), ('a', 2)], [('c', 1), ('b', 2)]]

  • El resultado es exactamente lo que quiero, pero ¿es posible compartir la lógica detrás de cómo hacerlo? Si convierto mi código a C o Java, no tendré acceso a zip o itertools (aunque hacen la vida muy, muy fácil)

    – usuario1735075

    17/10/2012 a las 13:39

  • @user1735075 Echa un vistazo a la documentación

    – ranura

    17/10/2012 a las 13:40

  • @ user1735075: ¿sabe que Python es de código abierto? Así que simplemente puede descargar las fuentes y ver qué hacen. +1 a Mr. Steak por señalar que la documentación en realidad tiene una implementación de muestra que no usa zip y similares

    – Bakuriu

    17/10/2012 a las 13:42

  • Literalmente no puedo hacer que esto funcione, incluso con tu ejemplo… todo lo que obtengo es una lista de objetos zip… 😐

    – m1nkeh

    7 ago 2018 a las 10:00

  • @logic proporciona lo que debería ser la solución aceptada.

    – Bernhard Wagner

    14 jun 2019 a las 20:44

Estaba buscando una lista multiplicada por sí misma con solo combinaciones únicas, que se proporciona como esta función.

import itertools
itertools.combinations(list, n_times)

Aquí como un extracto de los documentos de Python en itertools Eso podría ayudarte a encontrar lo que estás buscando.

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

la mejor manera de averiguar todas las combinaciones para una gran cantidad de listas es:

import itertools
from pprint import pprint

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

el resultado será:

[('a', 'd', 'e'),
 ('a', 'd', 'f'),
 ('b', 'd', 'e'),
 ('b', 'd', 'f'),
 ('c', 'd', 'e'),
 ('c', 'd', 'f')]

  • Gracias, gran respuesta!

    – toinbis

    27 ago. 2019 a las 15:30

Avatar de usuario de Fletch F Fletch
Fletch F Fletch

O la respuesta de KISS para listas cortas:

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

No es tan eficaz como itertools, pero está utilizando Python, por lo que el rendimiento ya no es su principal preocupación…

¡Me gustan todas las otras respuestas también!

  • Gracias, gran respuesta!

    – toinbis

    27 ago. 2019 a las 15:30

Avatar de usuario de Idanmel
Idanmel

Es posible que desee probar una lista de comprensión de una línea:

>>> [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']

¿Ha sido útil esta solución?