2019.07.07 다중 리스트를 평평하게 만들자, flatten 함수와 재귀
오늘 보실 예시 코드입니다.
1
2
3
4
5
6
7
8
| def flat_list(array):
a=[]
for i in array:
if type(i) == type(list()):
a+=(flat_list(i))
else:
a.append(i)
return a
|
오늘 튀어나온 개념들입니다.
- 재귀 함수
- list.append
- list.extend
저는 파이썬을 공부하면서 파이썬 문제들이 올라와 있는 사이트들을 활용합니다. 그
중 하나가 CheckiO 라는 사이트인데, 게임 마냥 문제를
풀면 레벨 업도 하고, 업적 시스템도 있어 업적을 따내면 보상도 받습니다. 좀 더 코딩을 재미있게 배우고자 하시는 분들에게 추천 드립니다. 링크는
다음과 같습니다.
CheckiO 문제를 열심히 풀고 있던 도중에, 다중 리스트를 일 차원 리스트로 변환시키는, 이른바 flatten list 문제에 발목을 잡히고 말았습니다. 제 우둔한
머리로는 이걸 풀 만한 효율적인 방법을 찾지 못했습니다. 무한 반복을 좋아하는 저 이기에, 다중 for문도 넣어보고 while로
무한 루프를 돌려보고 별 생 X랄을 다 해보았지만 헛수고였습니다.
결국 포기한 저는 마지막 수단을 사용하기로 했습니다. 구글링입니다. 의외로 flatten에 대한 여러 방법들이 존재하더군요. 그 중에 한 방법이 저의 뇌에 벼락을 내리 꽂았습니다.
![]() |
| 오오오오옷?! |
오늘은 제 뇌에 번개를 꽂아버린 방법을 소개해 드릴까 합니다. 구글에
‘flatten 함수’ 를 검색하시면 다중 리스트를, 후려
맞은 돈까스 패티 마냥 납작하게 만들어 버리는 방법이 다양하게 존재합니다. 한번 검색해보세요.
그렇다면 바로 코드를 보시도록 하겠습니다. 예시 코드는 다음과 같습니다.
1
2
3
4
5
6
7
8
| def flat_list(array):
a=[]
for i in array:
if type(i) == type(list()):
a+=(flat_list(i))
else:
a.append(i)
return a
|
보자마자 무릎을 탁 쳤습니다. 성능이 파워풀 한데다가 간결하기 까지… 역시 코드는 간결하고 읽기
쉬워야 합니다. 요 근래 파이썬을 공부하면서 본 몇 안되는 아름다운 코드 일 겁니다.
너무 찬양 일색이었네요, 다시 돌아가겠습니다. 이 함수를 사용하면 어떤 덩어리진 리스트 들이라도
매우 납작하게 만들어 낼 수 있습니다. 예시를 들자면,
이런 추악한 리스트도 저
함수를 거친다면
아주 아름답게 평평 해집니다.
그렇다면 어떤 원리로 다중
리스트를 일 차원으로 변형시키는 걸까요? 그건 함수 내부에 있는,
a+=flat_list(i)
이 코드 한 줄이 모든
리스트를 평평하게 만들어버리는 장본인입니다. 그렇습니다, 함수가
자기 자신을 다시 호출하는 재귀 함수입니다. 재귀 함수의 자세한 설명은 위키피디아에 올라와 있습니다.
그렇다면 이 코드에서 어떤
식으로 작동하는 지 좀더 파악해보도록 하겠습니다. 예시 코드 중간에 print()를
사용하여 값들을 확인해보겠습니다. 위의 사례는 보기가 어려우니까, 좀
더 단순하게 리스트를 만들어서 확인해 보도록 하겠습니다.
print()는 for문 바로 밑에 넣어 리스트의 값이 어떻게 추출되는
지 확인했습니다. 함수에 이 리스트를 넣은 결과 다음과 같이 결과가 나왔습니다.
그럼 차근차근 알아보도록
할까요?
먼저 1이 출력되었습니다. 반복문에 리스트를 넣으면, 리스트의 값들이 차례대로 추출된다는 것을 알고 계실 겁니다. 위의
리스트 첫번째 값은 숫자 1이기에 잘 출력이 되었네요. 그리고
이 1은,
if type(i) == type(list()):
이 코드에서 False 먹고 빠꾸 당합니다. 그럼 else를 타고 가서,
a.append(i)
저장용 리스트 a로 들어갑니다.
append() 함수는 리스트에 값을 추가해주는 기능을 가지고 있습니다. append 말고
+나, extend 등 리스트에 값을 넣는 방법은 다양하게
있습니다. 자세한 설명은 documentation에서 확인하면
됩니다.
다음 값은 [2] 입니다. 리스트
타입이군요. if문에 걸려버렸습니다. 이제부터 시작입니다.
a+=(flat_list(i))
[2]를 함수에 집어넣고, 그 리턴 값을 저장용 리스트 a에 넣습니다. [2]가 함수에 들어가서 다시 for문으로 들어갑니다. for문은 리스트의 값을 하나씩 추출해주니,
2를 출력했네요. 이 2는 리스트 타입이 아닌 int 타입이므로 if문에서 빠꾸 먹고 저장 리스트 a로 들어가게 됩니다. 그리고 [2] 리스트에는 값이 한 개 뿐이니, for문은 끝나버립니다. 이 a를
리턴 합니다.
그렇다면 실질적으로,
a+=(flat_list(i))
위의 식은 a+=[2] 과 동일한 식이 되겠군요. 현재 a는 [1] 이므로,
이것을 계산하게 됩니다. 결과는 위와 같이 나옵니다. 파이썬에서는 리스트 끼리 + 연산을 할 경우, 리스트 내부의 값들을 연산하지 않고, 안의 내용물 끼리 합쳐 새로운 리스트를 만들어 냅니다. 이 코드는
a.extend(flat_list(i))
이렇게 쳐도 그대로 작동합니다. extend 함수는 ‘리스트 안의 내용물을 합쳐 새로운 리스트를 만든다’는 개념이기에, 동작방식이 똑같습니다. 좀 더 코드를 전문적으로 보이고 싶으면
저걸 활용해도 괜찮겠네요.
그렇게 [1,2] 리스트를 만들어 내고, for문은 끝이 났으므로 [1,2] 리스트를 리턴 합니다. 결과도 그대로 나왔네요. 이렇게 복잡해 보이는 다중 리스트가 1차원 형태의 리스트로 바뀌어서 나왔습니다.
다른 다중 리스트들도 잘 풀어내는지 궁금하신 분은 코드를 복사해 가서 마음껏 테스트해봐도 좋습니다. 여러분도 이 함수를 써보면서, 저와 같은 ‘뒤통수 맞은 듯한’ 기분을 느껴 보셨으면 합니다. 새롭고 짜릿한 발견은 늘 즐겁고, 코딩 공부에 활기를 불어넣어 주니까요.








댓글
댓글 쓰기