여러 리스트에 걸쳐 서로소(disjoint) 관계, 즉 공통으로 포함된 문자가 하나도 없는 문자열 조합을 찾아야 하는 경우가 있습니다. 이럴 때는 두 개의 매개변수를 받는 제너레이터 함수를 정의한 뒤, functools 모듈의 reduce와 lambda를 if 조건과 함께 활용하여 결과를 도출할 수 있습니다.
아래는 실제 구현 예제입니다.
예제 코드
from functools import reduce
def determine_disjoint_pairs(disjoint_data, my_result=[]):
if not disjoint_data and not reduce(lambda a, b: set(a) & set(b), my_result):
yield tuple(my_result)
elif disjoint_data:
yield [idx for k in disjoint_data[0] for idx in determine_disjoint_pairs(disjoint_data[1:], my_result + [k])]
my_list_1 = ["python", "is", "fun"]
my_list_2 = ["its", "awesome", "learning"]
print("The first list is : ")
print(my_list_1)
print("The second list is :")
print(my_list_2)
my_result = list(determine_disjoint_pairs([my_list_1, my_list_2]))
print("The result is :")
print(my_result)
출력 결과
The first list is :
['python', 'is', 'fun']
The second list is :
['its', 'awesome', 'learning']
The result is :
[('fun', 'its'), ('fun', 'awesome')]
동작 원리
determine_disjoint_pairs라는 이름의 제너레이터 함수가 정의되며, 이 함수는 두 개의 매개변수를 받습니다.첫 번째 매개변수(
disjoint_data)가 비어 있고,reduce와lambda를 사용해 계산한 집합 교집합 결과도 거짓(빈 집합)이라면,yield연산자로 결과를 생성하며 이 값은 튜플(tuple)로 변환됩니다.그렇지 않고 아직 처리할 데이터가 남아 있다면, 리스트 컴프리헨션(list comprehension)과 함께
yield를 사용하면서, 나머지 데이터와 누적 결과를 새로운 매개변수로 전달해 함수를 재귀적으로 호출합니다.함수 외부에서는 두 개의 문자열 리스트가 정의되고 콘솔에 출력됩니다.
이 두 리스트를 담은 리스트를 인자로 전달하여 함수를 호출합니다.
호출 결과는
list()로 변환되어 변수에 할당됩니다.마지막으로 해당 변수가 콘솔에 출력됩니다.
왜 일부 조합만 결과에 포함될까?
출력 결과에서 ('fun', 'its')와 ('fun', 'awesome')만 반환된 이유는, 알고리즘이 두 문자열이 공통 문자를 공유하는지 집합 교집합으로 검사하기 때문입니다. 예를 들어 'python'과 'its'는 모두 문자 't'를 포함하므로 서로소가 아니어서 제외되고, 'fun'은 두 리스트의 어떤 문자열과도 공통 문자가 없어 유효한 조합으로 인정됩니다.