이것저것 공부 기록하기

[Python] permutation , combination, product 활용하기 본문

CS/Python

[Python] permutation , combination, product 활용하기

얍욥얍 2021. 9. 28. 12:32

하나 혹은 여러 개의 리스트가 주어졌을 때, 해당 리스트 내의 값들로 특정 경우의 수를 구해야 할 때가 있습니다. 다음과 같은 리스트가 있다고 해봅시다.

 

fruits_li=['사과', '배', '바나나']

 

이 중 2개의 과일을 고르는 수는 몇 가지일까요? 그렇게 어려운 문제처럼 보이진 않습니다. 하지만 리스트가 늘어나면 어떨까요? 

 

 

fruits_li=['사과', '배', '바나나']
bread_li=['식빵', '소보루빵', '크림빵']
drink_li=['주스', '맥주', '요거트']

위의 리스트 내의 값들로 특정 경우의 수를 구하려면 어떻게 해야할까? 파이썬 라이브러리 itertools에는 여러 가지 내장함수가 존재하고, 순열(permutation) 조합(combination)도 있습니다. 다음과 같이 라이브러리를 불러와 봅시다. 

 

from itertools import permutations, combinations

1. 단일 리스트 내 값들의 순열, 조합 구하기

과일 리스트에서 2개의 과일을 살 때 몇 가지의 경우의 수가 있을지 구해보겠습니다. 

 

from itertools import permutations, combinations

fruits_li=['사과', '배', '바나나']
bread_li=['식빵', '소보루빵', '크림빵']
drink_li=['주스', '맥주', '요거트']


# 각 리스트에서 N개만큼 뽑아 나열할 경우(순서 고려)
per_fruits=list(permutations(fruits_li, 2)) # N=2
print(per_fruits)

>> [('사과', '배'), ('사과', '바나나'), ('배', '사과'), ('배', '바나나'), ('바나나', '사과'), ('바나나', '배')]

 

보다시피 한 리스트 안에 튜플 형식으로 경우의 수들이 들어있는 것을 볼 수 있습니다. 그런데 ('사과', '배'), ('배', '사과')가 서로 다른 경우로 되어 있습니다. ('사과', '바나나'), ('바나나', '사과')도 마찬가지고요. 이렇게 순서가 바뀐 경우를 고려하지 않으려면 순열이 아닌 조합(combination)을 사용해야 합니다. 다시 가보겠습니다. 

 

# 각 리스트 나열 시 N개만큼 뽑아 나열할 경우 출력(순서 고려하지 않음)
fruits_con=list(combinations(fruits_li, 2)) # N=2
print(fruits_con)

>> [('사과', '배'), ('사과', '바나나'), ('배', '바나나')]

 

경우의 수가 잘 뽑혔습니다. 하지만 사과를 두 개 살 수도 있고, 바나나를 두 개 살 수도 있는 경우도 있을 겁니다. 상식적으로 과일 가게에 과일이 딱 하나만 놓여있지는 않을 테니까요. 이럴 경우에는 값이 중복되는 것을 허용하는 다른 내장함수 combinations_with_replacement를 사용해야 합니다. 

 

from itertools import permutations, combinations, combinations_with_replacement

# 각 리스트 나열 시 N개만큼 뽑아 나열할 경우 출력(순서 고려하지 않음, 중복 허용)
fruits_con2=list(combinations_with_replacement(fruits_li, 2)) # N=2
print(fruits_con2)

>> [('사과', '사과'), ('사과', '배'), ('사과', '바나나'), ('배', '배'), ('배', '바나나'), ('바나나', '바나나')]

 

모든 경우의 수가 출력되는 것을 볼 수 있습니다. 값들의 순서를 고려해야 한다면 permutation을, 그렇지 않다면 combinations를 사용하면 됩니다. 만약 combinations에서도 같은 값들이 중복되는 경우를 포함하고 싶다면 combinations_with_replacement를 쓰면 되겠습니다. 

 

 

2. 두 개 이상의 리스트에서 조합 구하기

이번에는 두 개 이상의 리스트에서 N개의 값들을 뽑는 방법을 알아보겠습니다. 위의 빵 리스트와 음료수 리스트에서 하나씩을 뽑는 경우를 찾아보겠습니다. 이럴 때는 또 다른 내장함수인 product를 사용합니다. 

 

from itertools import permutations, combinations, combinations_with_replacement, product

bread_li=['식빵', '소보루빵', '크림빵']
drink_li=['주스', '맥주', '요거트']

# 2개의 리스트로 만들 수 있는 경우의 수
two_li=[bread_li,drink_li]
two_con=list(product(*two_li))
print(two_con)


>> [('식빵', '주스'), ('식빵', '맥주'), ('식빵', '요거트'), ('소보루빵', '주스'), ('소보루빵', '맥주'), ('소보루빵', '요거트'), ('크림빵', '주스'), ('크림빵', '맥주'), ('크림빵', '요거트')]

 

보다시피 빵-음료수의 모든 조합이 나온 것을 볼 수 있습니다. 세 개의 리스트를 활용하는 경우도 이와 마찬가지입니다. 과일 하나, 빵 하나, 맥주 하나를 뽑는 경우는 다음과 같습니다.

 

# 3개의 리스트에서 구할 수 있는 모든 조합
all_li=[fruits_li,bread_li,drink_li]
all_con=list(product(*all_li))
print(all_con)

>> [('사과', '식빵', '주스'), ('사과', '식빵', '맥주'), ('사과', '식빵', '요거트'), ('사과', '소보루빵', '주스'), ('사과', '소보루빵', '맥주'), ('사과', '소보루빵', '요거트'), ('사
과', '크림빵', '주스'), ('사과', '크림빵', '맥주'), ('사과', '크림빵', '요거트'), ('배', '식빵', '주스'), ('배', '식빵', '맥주'), ('배', '식빵', '요거트'), ('배', '소보루빵', ' 
주스'), ('배', '소보루빵', '맥주'), ('배', '소보루빵', '요거트'), ('배', '크림빵', '주스'), ('배', '크림빵', '맥주'), ('배', '크림빵', '요거트'), ('바나나', '식빵', '주스'), (' 
바나나', '식빵', '맥주'), ('바나나', '식빵', '요거트'), ('바나나', '소보루빵', '주스'), ('바나나', '소보루빵', '맥주'), ('바나나', '소보루빵', '요거트'), ('바나나', '크림빵', ' 
주스'), ('바나나', '크림빵', '맥주'), ('바나나', '크림빵', '요거트')]

 

번외로 튜플로 되어있는 리스트 요소들의 값은 다음과 같이 출력하면 되겠습니다.

ans = [''.join(x) for x in product(*all_con)]

# 또는
ans = list(map(list, product(*tmp)))

 


References

https://hengbokhan.tistory.com/

https://hckcksrl.medium.com/

반응형
Comments