두 목록 사이의 조합?


187

시간이 지났고 내가 만들려고하는 알고리즘으로 머리를 감싸는 데 문제가 있습니다. 기본적으로 두 개의 목록이 있으며 두 목록의 모든 조합을 원합니다.

나는 그것을 올바르게 설명하지 않을 수 있으므로 여기에 예가 있습니다.

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

이 경우 출력은 다음과 같습니다.

1.  A1 B2
2.  B1 A2

까다로운 부분은“number”변수의 항목보다“name”변수에 더 많은 항목이있을 수 있다는 것입니다 (number는 항상 name 변수와 같거나 작습니다).

나는 모든 조합 (루프에 중첩되어 있습니까?)을 수행하는 방법을 혼란스럽고 숫자 목록에있는 것보다 이름에 더 많은 항목이있는 경우 이름 변수의 항목을 이동하는 논리에 더 혼란 스럽습니다.

나는 최고의 프로그래머는 아니지만 누군가가 이것을 달성하기 위해 논리 / 알고리즘을 명확히하도록 도울 수 있다면 기회를 줄 수 있다고 생각합니다. 그래서 나는 방금 중첩 된 루프에 붙어 있습니다.

최신 정보:

다음은 3 개의 변수와 2 개의 숫자가있는 출력입니다.

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

산출:

1.  A1 B2
2.  B1 A2
3.  A1 C2
4.  C1 A2
5.  B1 C2
6.  C1 B2


1
@ dm03514 나는 그것을 보았고 itertools를 사용하여 다소 비슷한 목표에 대한 예제를 찾았지만 파이썬으로 프로토 타이핑하고 있지만 다른 언어로 최종 코드를 작성하므로 다른 방법으로는 사용할 수없는 도구를 사용하고 싶지 않습니다.
user1735075

1
당신이 요구하는 것은 실제로 이해가되지 않습니다. 첫 번째 목록에 A, B, C가 있고 두 번째 목록에 1,2가 있으면 어떤 결과를 기대하십니까? 당신이 한 예가 한 글자와 네 개의 숫자 (A1, A2, B1, B2)에 대해 4 가지 다른 결과를 가지거나 두 목록의 크기가 같은 경우에 수행 할 수 있습니다.
interjay

1
인터 제이에 동의합니다. 같지 않은 크기의 경우 결과를 지정하십시오. 그렇지 않으면 일반적인 솔루션을 제공 할 수 없습니다.
Bakuriu

안녕하세요 여러분, 3 개의 이름과 2 개의 숫자로 출력을 표시하도록 답변을 업데이트했습니다. 나는 왜 downvote인지 잘 모르겠습니다.
user1735075

답변:


93

참고 :이 답변은 위에 나온 특정 질문에 대한 것입니다. Google에서 왔으며 Python으로 Cartesian 제품을 얻는 방법을 찾고 itertools.product있거나 간단한 목록 이해가 원하는 것일 수 있습니다. 다른 답변을 참조하십시오.


가정 해 봅시다 len(list1) >= len(list2). 그럼 당신이 원하는에 표시하는 길이되는 모든 변경 걸릴 것입니다 len(list2)에서를 list1하고리스트 2에서 항목을 일치합니다. 파이썬에서 :

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

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

보고

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

1
결과는 정확히 내가 원하는 것이지만 그것을 수행하는 방법 뒤에 논리를 공유 할 수 있습니까? 코드를 C 또는 Java로 변환하면 zip 또는 itertools에 액세스 할 수 없습니다 (생명을 매우 쉽게 만들 수 있음)
user1735075


1
@ user1735075 : 파이썬이 오픈 소스라는 것을 알고 있습니까? 소스를 다운로드하여 무엇을하는지 확인할 수 있습니다. Mr. Steak에게 문서에 실제로 사용되지 않고 zip유사한 샘플 구현이 있음을 지적한 Mr.
Bakuriu

2
나는 당신의 예제에서도 말 그대로 이것을 작동시킬 수 없습니다 ... 내가 얻는 모든 것은 zip 객체의 목록입니다 .. : |
m1nkeh

1
@logic은 허용되는 솔루션을 제공합니다.
Bernhard Wagner

500

가장 간단한 방법은 다음을 사용하는 것입니다 itertools.product.

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

11
OP는 카티 전 곱을 요구하지 않았으며이 답변 (대부분의 다른 답변)은 질문에 지정된 예상 결과를 제공하지 않습니다.
interjay

17
@ interjay 당신은 매우 옳지 만 너무 많은 사람들 이이 답변을 올바른 것으로 생각하면 질문의 제목에 컨텍스트가 없다고 가정 할 수 있습니다.
xpy

3
@xpy 제목이 너무 짧아서 모든 것을 설명 할 수 없습니다. 그래서 실제 질문을 읽어야합니다.
interjay

10
OP는 퍼머 레이션을 원했지만 Google은 나 같은 조합을 찾는 사람을이 답변에 보냅니다. 투표가 8 배나되는 것을 보게되어 기쁩니다!
Josh Friedlander

160

위의 가장 간단한 것보다 간단 할 수 있습니다.

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

수입없이


최고의 솔루션! 감사합니다! 다른 해결책은 명백하지 않거나 a> b 등과 같은 특정한 경우에만 작동합니다.
Philipp Schwarz

3
가장 파이썬적인 솔루션! (그리고 불필요한 수입을 피합니다)
Dalker

6
시간 복잡도는 O (n ^ 2)입니다.
Deepak Sharma

2
베팅 솔루션 !! 맨 손으로 기본은 항상 가장 좋은 방법입니다
Sabyasachi

22

나는이 기능으로 제공되는 유일한 조합만으로 그 자체를 곱한 목록을 찾고있었습니다.

import itertools
itertools.combinations(list, n_times)

다음 은 Python 문서에서 itertools 발췌 한 내용 입니다. 원하는 내용을 찾는 데 도움이 될 수 있습니다.

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

11

한 줄 목록 이해를 시도 할 수 있습니다.

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

11

많은 수의 목록에 대한 모든 조합을 찾는 가장 좋은 방법은 다음과 같습니다.

import itertools
from pprint import pprint

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

결과는 다음과 같습니다.

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

고마워, 좋은 대답!
toinbis

10

또는 짧은 목록에 대한 KISS 답변 :

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

itertools만큼 성능이 좋지 않지만 파이썬을 사용하고 있으므로 성능은 이미 주요 관심사가 아닙니다 ...

나는 다른 모든 답변도 좋아합니다!


8

interjay의 답변을 약간 개선하여 결과를 평평한 목록으로 만듭니다.

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

링크 에서 참조


4

itertools없이

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

4

"두 개의 목록을 제공하고 각 목록에서 한 항목 쌍의 가능한 모든 순열을 찾으십시오"라는 질문에 대답하고 기본 Python 기능 (예 : itertools없이)을 사용하여 다른 프로그래밍 언어를 쉽게 복제 할 수 있습니다.

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)

보고

[['a1', 'b2'], ['a1', 'c2'], ['a2', 'b1'], ['a2', 'c1'], ['b1', 'c2'], ['b2', 'c1']]

2

이에 대한 더 나은 답변은 제공된 특정 길이의 목록에 대해서만 작동합니다.

다음은 모든 길이의 입력에서 작동하는 버전입니다. 또한 수학적 조합과 치환의 개념에서 알고리즘을 명확하게 만듭니다.

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}')

이 결과는 다음과 같습니다.

0: A1 B2
1: A1 C2
2: B1 A2
3: B1 C2
4: C1 A2
5: C1 B2
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.