가끔 코딩 테스트에서 이거.. 리스트를 평탄화해주면 쉽게 풀 수 있겠는데? 라는 생각이 들 때가 있습니다. 프로그래머스 0단계에서는 이 평탄화 함수를 작성하는 것 자체가 문제로 출제되기도 했었던거 같기도 하구요. 어쨌든 알고 있으면(또는 외워 두면) 정말 너무나!!!! 큰 도움이 되는!!!!! 평탄화 함수 작성하는 방법!!! 정리해 봅시다.
* 설명 없이 함수만 빠르게 확인하고 싶으시다면 글 맨 아래로 가세요! *
먼저, 중첩 리스트란 무엇일까요?
normal_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
weird_list = [1, 2, [3], 4, 5, [6], 7, [8, 9, 10]]
crazy_list = [1, 2, [[3], 4, 5], [[6], 7, [8, [9, [10]]]]]
위 세 가지 리스트를 살펴 봅시다.
먼저 멀쩡한 리스트 normal_list는 참 보기 좋습니다.
그런데 weird_list는 리스트 안에 리스트를 원소로 가지고 있네요. [3], [6], [8, 9, 10]과 같이 말이죠. 이런 놈들을 중첩 리스트라고 부르겠습니다. 그래도 여기까진 어찌저찌 해체해볼 수 있을 것 같습니다.
그런데 crazy_list.. 이 미친놈을 보니까 리스트 안에 리스트가 또 리스트를 가지고 있어요. 중첩에 중첩에 중첩에 중첩에 중...!!!
평탄화란? (Flatten)
weird_list, crazy_list, crazy_list_and_tuple처럼 중첩된 리스트를
normal_list처럼 1차원의 리스트로 평평(Flat)하게 평탄화(Flatten)해주는 작업을 의미합니다.
만약 우리가 리스트 안에 있는 모든 값들 중에서 가장 큰 값을 구해야 된다면 어떻게 할까요?
normal_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
max(normal_list)
# 10
crazy_list = [1, 2, [[3], 4, 5], [[6], 7, [8, [9, [10]]]]]
max(crazy_list)
# ????????
1차원 리스트인 normal_list의 경우 내장함수 max()를 사용하면 아주 쉽게 최댓값을 구해낼 수 있지만, 우리의 미친놈 crazy_list는 그렇게 호락호락하지가 않습니다.
평탄화 함수 작업하기
리스트 안에 리스트가 들어가 있는 중첩 리스트를 하나의 리스트로 평탄화(Flatten)하는 회귀함수를 작성해 봅니다. 먼저 weird_list를 가지고 생각을 열어 보겠습니다.
weird_list = [1, 2, [3], 4, 5, [6], 7, [8, 9, 10]]
def easy_flatten(nested_list):
result = []
for element in nested_list:
if isinstance(element, list):
result.extend(element)
else:
result.append(element)
return result
easy_flatten(weird_list)
# [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
weird_list의 원소를 하나씩 점검합니다. 만약 원소가 리스트라면 result에 그 리스트를 extend해서 합쳐 주고, 원소가 리스트가 아니라면 해당 원소를 append를 이용해서 result에 추가해 줍니다. weird_list가 예쁘게 평탄화된 것을 확인할 수 있습니다.
그렇다면 easy_flatten 함수를 가지고 crazy_list도 평탄화 작업이 될까요?
crazy_list = [1, 2, [[3], 4, 5], [[6], 7, [8, [9, [10]]]]]
easy_flatten(crazy_list)
# [1, 2, [3], 4, 5, [6], 7, [8, [9, [10]]]]
우리가 원하는 결과가 나오지 않았습니다. 중첩에 중첩이 여러번 반복되는 경우를 생각해주지 못했기 때문입니다. 그렇다면 여러 개의 중첩을 풀어주는 함수를 어떻게 작성할 수 있을까요? 중첩이 몇 번 반복되는지 알 수 없다는 점에 착안하여, 재귀함수(recursion)를 작성해 보겠습니다.
재귀함수를 적용한 Flatten 함수
def hard_flatten(nested_list):
result = []
for element in nested_list:
if isinstance(element, list):
# 유일하게 달라진 부분 - element 대신 hard_flatten(element)❤️
result.extend(hard_flatten(element))
else:
result.append(element)
return result
만약 nested_list의 element가 list 객체라면 result에 hard_flatten(element)를 추가해주도록 재귀함수가 작성되었습니다. 이렇게 여러 번 중첩이 반복되는 경우 자기 자신을 호출함으로써 문제를 간단히 해결할 수 있게 되었습니다.
crazy_list = [1, 2, [[3], 4, 5], [[6], 7, [8, [9, [10]]]]]
hard_flatten(crazy_list)
#[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
우리가 원하는 결과값을 얻었네요!
이 리스트 평탄화 함수는 여러 번 작성해보시면서 외워 두시면 필요할 때 요긴히 사용하실 수 있을거에요.
(적용 예시)
# 리스트 k에서 하트를 모두 제거한 1차원 리스트를 출력하세요
k = [['a', 'b', ['🩶', 'd']], 'e', 'f', '🩶', [['🩶'], 'i']]
[element for element in hard_flatten(k) if element != '🩶']
# ['a', 'b', 'd', 'e', 'f', 'i']
감사합니당!
'Code > function snippet' 카테고리의 다른 글
python | numpy 라이브러리를 이용하여 최대공약수, 최소공배수 구하기 (gcd, lcm) (0) | 2024.04.08 |
---|---|
python | 연속 공백 여러개 분리하기, split 함수 대신 정규식(re) 활용하기! (0) | 2024.04.08 |
python | 재귀함수 (팩토리얼 예제) (0) | 2024.04.01 |
python | 소수 판별 함수 작성하기 (prime number) (0) | 2024.04.01 |
python | 약수(factor) 리스트업 함수 작성하기 + 메모화 (memorization) (0) | 2024.04.01 |