일련의리스트의 데카르트 곱을 얻으시겠습니까?


317

목록 그룹에서 Cartesian 제품 (가능한 모든 값 조합)을 얻으려면 어떻게해야합니까?

입력:

somelists = [
   [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) ...]

24
카티 전 곱에서는 중복이 허용되므로 '가능한 모든 조합'은 '카테 시안 곱'과 동일하지 않습니다.
Triptych

7
직교 제품의 복제되지 않은 버전이 있습니까?
KJW

16
@KJW 예,set(cartesian product)
NoBugs

5
입력 목록에 중복 항목이 포함되어 있지 않은 경우 데카르트 제품에는 중복 항목이 없어야합니다. Cartesian 제품에서 중복을 원하지 않으면 set(inputlist)모든 입력 목록을 사용 하십시오. 결과에 없습니다.
CamilB

@Triptych 무엇? 카티 전 곱의 표준 정의는 세트입니다. 왜 그렇게 많은 사람들이 공감합니까?
PascalIv

답변:


378

itertools.product

Python 2.6에서 사용 가능합니다.

import itertools

somelists = [
   [1, 2, 3],
   ['a', 'b'],
   [4, 5]
]
for element in itertools.product(*somelists):
    print(element)

어느 것과

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

22
OP에서 제공 한 변수 somelist를 사용하는 경우 '*'문자를 추가하고 싶었습니다.
brian buck

1
@jaska : 결과에 요소를 product()생성 nitems_in_a_list ** nlists합니다 ( reduce(mul, map(len, somelists))). 하나의 요소를 산출하는 것은되지 않는다는 것을 믿을 이유가 없다 O(nlists)즉 (상각)이, 시간 복잡성과 동일 간단한 중첩 된 for-loops : 질문에 입력, 예를 들어, nlists=3결과에있는 요소의 총 수는 : 3*2*2및 각 요소에는 nlists항목 이 있습니다 ( 3이 경우).
jfs

2
*일부리스트 이전 의 사용은 무엇입니까 ? 무엇을합니까?
Vineet Kumar Doshi

6
@VineetKumarDoshi : 여기에서 함수 호출에 대한 여러 인수로 목록을 해제하는 데 사용됩니다. 자세한 내용은 여기 읽기 : stackoverflow.com/questions/36901/...
모 베르그

4
참고 : 각 목록에 하나 이상의 항목이 포함 된 경우에만 작동합니다
igo

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

38

Python 2.5 이상인 경우 :

>>> [(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)]

다음은 재귀 버전입니다 product()(단지 예시).

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

예:

>>> 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())
[()]

일부 args반복자 인 경우 재귀 버전이 작동하지 않습니다 .
jfs 2012

20

itertools.product :

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

6
*일부리스트 이전 의 사용은 무엇입니까 ?
Vineet Kumar Doshi

@VineetKumarDoshi "product (somelists)" 는 파이썬이 먼저 요소로 "[1, 2, 3]" 을 얻은 다음 하위 comman 이후에 다른 요소를 얻는 방식으로 하위 목록 사이의 데카르트 곱 이며 첫 번째 제품입니다. 용어는 ([1, 2, 3],)이며, 두 번째 ([4, 5])와 유사하므로 "[([1, 2, 3],), ([4, 5],), ( [6,7])] " . 튜플 내부의 요소 사이에 직교 곱을 얻으려면 튜플 구조에 대해 Asterisk와 함께 Python에 알려야합니다. 사전에는 **를 사용합니다. 여기 더 .
hhh

19

나는 목록 이해력을 사용할 것입니다 :

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

1
나는 목록 이해를 사용 하여이 솔루션을 정말로 좋아합니다. 왜 더 많이지지되지 않는지 모르겠습니다. 너무 간단합니다.
llekn

20
@llekn 코드가 목록의 수에 고정되어있는 것 같습니다
Bằng Rikimaru

11

다음은 임시 목록을 저장하지 않는 재귀 생성기입니다.

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

산출:

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

1
그러나 스택에 저장됩니다.
Quentin Pradet

@QuentinPradet 당신은 같은 def f(): while True: yield 1크기 의 생성기 가 스택 크기를 계속 증가시킬 것입니까?
Anurag Uniyal

@QuentinPradet 예, 그러나이 경우에도 전체 목록이 아니라 최대 깊이에 필요한 스택 만 필요
하므로이

사실이야, 미안 벤치 마크가 흥미로울 수 있습니다. :)
Quentin Pradet

11

Python 2.6 이상에서는 'itertools.product`를 사용할 수 있습니다. 이전 버전의 Python에서는 최소한 시작점으로 문서에서 다음과 같은 (거의-설명서 참조) 동등한 코드를 사용할 수 있습니다 .

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)

둘 다의 결과는 반복자이므로 실제로 처리를 위해 목록이 필요한 경우을 사용하십시오 list(result).


문서에 따라 실제 itertools.product 구현은 중간 결과를 빌드하지 않으므로 비용이 많이들 수 있습니다. 이 기술을 사용하면 적당한 크기의 목록에서 상당히 빨리 벗어날 수 있습니다.
Triptych 2019

4
나는 OP를 문서 만 가리키고 읽을 수는 없습니다.

1
설명서의 코드는 이전 버전의 Python에 대한 해결 방법이 아니라 제품 기능의 기능을 보여주기위한 것입니다.
Triptych 2016 년

9

이미 많은 답변이 있지만 내 생각 중 일부를 나누고 싶습니다.

반복적 접근

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

재귀 접근

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]

람다 접근

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

"반복적 접근"에서 결과가 result = [[]]로 선언 된 이유는 list_of_list라는 것을 알고 있지만 일반적으로 list_of_list를 선언하더라도 [[]]가 아닌 []를 사용합니다.
Sachin S

저는 Pythonic 솔루션 측면에서 약간 새로운 사람입니다. 귀하 또는 일부 통행인이 "반복적 접근 방식"으로 목록 이해를 별도의 루프로 작성 하시겠습니까?
Johnny Boy

4

재귀 접근법 :

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)

반복 접근법 :

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)

3

가변성 풍미에서 위의 재귀 생성기 솔루션을 약간 수정했습니다.

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

물론 래퍼는 해당 솔루션과 정확히 동일하게 작동합니다.

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

한 트레이드 오프 : 그것을 확인 재귀 각 외부 루프에 중단해야하는 경우, 그리고 하나 개의 이득 : 예를 들어, 빈 호출에 따라 어떤 수율, product(())나는 가정합니다 (doctest가 참조) 의미 적으로 더 정확한 것입니다.

리스트 이해에 관하여 : 수학적 정의는 임의의 수의 인수에 적용되는 반면,리스트 이해는 알려진 수의 인수 만 처리 할 수 ​​있습니다.


2

이미 말한 것에 약간을 추가하기 만하면 : sympy를 사용하면 문자열 대신 기호를 사용하여 수학적으로 유용 할 수 있습니다.

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

sympy .


1

나는 이것이 효과가 있다고 믿는다.

def cartesian_product(L):  
   if L:
       return {(a,) + b for a in L[0] 
                        for b in cartesian_product(L[1:])}
   else:
       return {()}

0

스톤 헨지 접근 방식 :

def giveAllLists(a, t):
    if (t + 1 == len(a)):
        x = []
        for i in a[t]:
            p = [i]
            x.append(p)
        return x
    x = []

    out = giveAllLists(a, t + 1)
    for i in a[t]:

        for j in range(len(out)):
            p = [i]
            for oz in out[j]:
                p.append(oz)
            x.append(p)
    return x

xx= [[1,2,3],[22,34,'se'],['k']]
print(giveAllLists(xx, 0))

산출:

[[1, 22, 'k'], [1, 34, 'k'], [1, 'se', 'k'], [2, 22, 'k'], [2, 34, 'k'], [2, 'se', 'k'], [3, 22, 'k'], [3, 34, 'k'], [3, 'se', 'k']]
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.