Frage

Wie kann ich das kartesische Produkt (jede mögliche Kombination von Werten) erhalten aus einer Gruppe von Listen?

Input:

somelists = [
   [1, 2, 3],
   ['a', 'b'],
   [4, 5]
]

Gewünschte Ausgabe:

[(1, 'a', 4), (1, 'a', 5), (1, 'b', 4), (1, 'b', 5), (2, 'a', 4), (2, 'a', 5) ...]
War es hilfreich?

Lösung

In Python 2.6 +

import itertools
for element in itertools.product(*somelists):
    print(element)

Dokumentation: Python 3 - itertools.product

Andere Tipps

import itertools
>>> for i in itertools.product([1,2,3],['a','b'],[4,5]):
...         print i
...
(1, 'a', 4)
(1, 'a', 5)
(1, 'b', 4)
(1, 'b', 5)
(2, 'a', 4)
(2, 'a', 5)
(2, 'b', 4)
(2, 'b', 5)
(3, 'a', 4)
(3, 'a', 5)
(3, 'b', 4)
(3, 'b', 5)
>>>

Für Python 2.5 und älter:

>>> [(a, b, c) for a in [1,2,3] for b in ['a','b'] for c in [4,5]]
[(1, 'a', 4), (1, 'a', 5), (1, 'b', 4), (1, 'b', 5), (2, 'a', 4), 
 (2, 'a', 5), (2, 'b', 4), (2, 'b', 5), (3, 'a', 4), (3, 'a', 5), 
 (3, 'b', 4), (3, 'b', 5)]

Hier ist eine rekursive Version von product() (nur eine Abbildung):

def product(*args):
    if not args:
        return iter(((),)) # yield tuple()
    return (items + (item,) 
            for items in product(*args[:-1]) for item in args[-1])

Beispiel:

>>> list(product([1,2,3], ['a','b'], [4,5])) 
[(1, 'a', 4), (1, 'a', 5), (1, 'b', 4), (1, 'b', 5), (2, 'a', 4), 
 (2, 'a', 5), (2, 'b', 4), (2, 'b', 5), (3, 'a', 4), (3, 'a', 5), 
 (3, 'b', 4), (3, 'b', 5)]
>>> list(product([1,2,3]))
[(1,), (2,), (3,)]
>>> list(product([]))
[]
>>> list(product())
[()]

itertools.product :

import itertools
result = list(itertools.product(*somelists))

Ich würde verwenden Liste Verständnis:

somelists = [
   [1, 2, 3],
   ['a', 'b'],
   [4, 5]
]

cart_prod = [(a,b,c) for a in somelists[0] for b in somelists[1] for c in somelists[2]]

In Python 2.6 und höher Sie ‚itertools.product` verwenden können. In älteren Versionen von Python können Sie die folgende verwenden (fast - siehe Dokumentation) gleichwertig Code aus der Dokumentation , zumindest als Ausgangspunkt:

def product(*args, **kwds):
    # product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy
    # product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111
    pools = map(tuple, args) * kwds.get('repeat', 1)
    result = [[]]
    for pool in pools:
        result = [x+[y] for x in result for y in pool]
    for prod in result:
        yield tuple(prod)

Das Ergebnis der beiden ist ein Iterator, wenn Sie also wirklich eine Liste für furthert Verarbeitung benötigen, verwenden list(result).

Hier ist ein rekursive Generator, der keine temporären Listen speichert

def product(ar_list):
    if not ar_list:
        yield ()
    else:
        for a in ar_list[0]:
            for prod in product(ar_list[1:]):
                yield (a,)+prod

print list(product([[1,2],[3,4],[5,6]]))

Ausgabe:

[(1, 3, 5), (1, 3, 6), (1, 4, 5), (1, 4, 6), (2, 3, 5), (2, 3, 6), (2, 4, 5), (2, 4, 6)]

Obwohl es bereits viele Antworten sind, würde Ich mag einige meiner Gedanken teilen:

Iterative Ansatz

def cartesian_iterative(pools):
  result = [[]]
  for pool in pools:
    result = [x+[y] for x in result for y in pool]
  return result

rekursive Ansatz

def cartesian_recursive(pools):
  if len(pools) > 2:
    pools[0] = product(pools[0], pools[1])
    del pools[1]
    return cartesian_recursive(pools)
  else:
    pools[0] = product(pools[0], pools[1])
    del pools[1]
    return pools
def product(x, y):
  return [xx + [yy] if isinstance(xx, list) else [xx] + [yy] for xx in x for yy in y]

Lambda-Ansatz

def cartesian_reduct(pools):
  return reduce(lambda x,y: product(x,y) , pools)

Nur ein wenig hinzuzufügen, was bereits gesagt wurde. Wenn Sie sympy verwenden, können Sie Symbole verwenden, anstatt Strings, die sie mathematisch nützlich macht

import itertools
import sympy

x, y = sympy.symbols('x y')

somelist = [[x,y], [1,2,3], [4,5]]
somelist2 = [[1,2], [1,2,3], [4,5]]

for element in itertools.product(*somelist):
  print element

Über sympy .

Eine geringfügige Modifikation der obigen rekursiven Erzeugungslösung in variadische Geschmack:

def product_args(*args):
    if args:
        for a in args[0]:
            for prod in product_args(*args[1:]) if args[1:] else ((),):
                yield (a,) + prod

Und natürlich ein Wrapper, der es genau so, wie diese Lösung die gleiche macht Arbeit:

def product2(ar_list):
    """
    >>> list(product(()))
    [()]
    >>> list(product2(()))
    []
    """
    return product_args(*ar_list)

mit einem Trade-off : es überprüft, ob die Rekursion bei jeder äußeren Schleife brechen soll, und einen Gewinn : kein Ertrag auf leeren Anruf, egproduct(()), die ich nehme an würde (siehe doctest) semantisch korrekt sein.

In Bezug auf Liste Verständnis: die mathematische Definition gilt für eine beliebige Anzahl von Argumenten, während Liste Verständnis nur mit einer begrenzten Anzahl von ihnen umgehen könnte

.

rekursive Ansatz:

def rec_cart(start, array, partial, results):
  if len(partial) == len(array):
    results.append(partial)
    return 

  for element in array[start]:
    rec_cart(start+1, array, partial+[element], results)

rec_res = []
some_lists = [[1, 2, 3], ['a', 'b'], [4, 5]]  
rec_cart(0, some_lists, [], rec_res)
print(rec_res)

iterativer Ansatz:

def itr_cart(array):
  results = [[]]
  for i in range(len(array)):
    temp = []
    for res in results:
      for element in array[i]:
        temp.append(res+[element])
    results = temp

  return results

some_lists = [[1, 2, 3], ['a', 'b'], [4, 5]]  
itr_res = itr_cart(some_lists)
print(itr_res)
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top