코딩테스트

[백준] 11720 숫자의 합 - 문제로 이해하는 이터러블(iterable), map() 함수, map 객체

futuregunmulju 2025. 4. 18. 05:38
반응형

문제

N개의 숫자가 공백 없이 쓰여있다. 이 숫자를 모두 합해서 출력하는 프로그램을 작성하시오.

입력

첫째 줄에 숫자의 개수 N (1 ≤ N ≤ 100)이 주어진다. 둘째 줄에 숫자 N개가 공백없이 주어진다.

출력

입력으로 주어진 숫자 N개의 합을 출력한다.

 

처음 쓴 코드

n = int(input())
num = input()

t = 0
for i in range(n):
    t += int(num[i])


print(t)

 

 

코딩테스트용 문법으로 수정

코딩테스트에서는 주어진 시간 내 간결함정확함이 생명이다.
그래서 이렇게 여러줄의 코드로 작성하면 하수가 되어버리는 것...
따라서, 코드 컨프리헨션이나 합성 함수 형태를 사용하자!

n = int(input())
num = input()

print(sum(map(int, num))) # 포인트!

마지막 줄 코드 실행 순서 설명:

1. 합성 함수 형태이므로 가장 안에 있는 코드부터 실행됨. map(int, num)
2. 문자열 num은 각 원소가 character인 배열임. 따라서 map()를 통해서 각 원소를 int로 바꿀 수 있음.
3. map()를 통해서 각 자리수를 int로 바꾼 map 객체를 반환 (딕셔너리 아닙니다).
4. sum()은 map 객체를 순회하면서 다 더함.
5. 마지막으로 출력!

이 문제에서 사용한 개념을 확인해보자.

 

 

 

 

map() 함수

map(함수명, 이터러블) 로 쓰인다.

리스트처럼 여러가지 원소를 한 번에 묶은 데이터를 두번째 파라미터에 넣고,
원소 하나하나에 적용하고자 하는 함수를 첫번째 파라미터에 넣어서 사용할 수 있다.

그러면 전체 리스트에 함수가 적용된 객체가 반환된다.
리스트의 원소, 즉 데이터를 함수에 일대일 mapping 해줘서 map함수라고 부르는 것 같다.

 

이터러블(Iterable)

map() 함수의 두번째 파라미터에는 사실 리스트만을 넣는게 아니라 이터러블(iterable)이라는 객체를 넣는데, 이를 조금 더 자세히, 명확히 이해해보자.

이터러블 "반복 가능한 객체"리스트, 튜플, 딕셔너리가 이 이터러블 집합에 속한다. 집합으로 표현하자면 다음과 같다.

{List, Tuple, Dictionary, Set, String 등등} ⊂ 이터러블

 

리스트, 튜플, 딕셔너리는 컬렉션형 데이터타입(collection datatype)인데 그러면 이터러블은 컬렉션형 데이터타입이랑 똑같은 거 아닌가? 같은 질문이 생길 수도 있는데,

똑같은 게 아니라 이터러블이 더 상위 개념, 더 포괄적인 개념이다.

부분 집합으로 표현하자면 (collection datatype ⊂ iterable) 이 된다.

이터러블에는 우리가 일반적으로 알고 있는 데이터타입 뿐만 아니라 다른 객체들도 있다.
range() 함수의 range 객체, iter(), file 객체도 파일을 열면 한 줄씩 읽어들이므로 반복 가능한 객체다.

 

개인적으로 이터러블이라는 단어가 생소해서 잘 받아들여지지 않았는데
이 글을 쓰면서 한 백 번은 봐주니까 좀 받아들여진 거 같다.
역시 양치기가 최고야..

 

 

map 객체

map 함수의 return value는 map 객체인데, map 객체는 또 뭔가 싶을 수도 있다. 

IDLE에서 map()의 return value가 어떻게 생겼는지 확인하려고 하면,

이렇게 데이터가 어디에 저장되어 있는지 주소(address)만 알려준다.

map() 을 실행하면 "실제 데이터가 바로 계산되어 저장되어 있는 게 아니라", 필요할 때 계산되도록 준비된 map 객체가 반환된다. 이걸 lazy evaluation (지연 평가) 이라고 한다. 

즉, 위의 사진에서 map() 가 실행되었을 때 저 상태에서는 숫자들이 뭐가 들어 있는지 안 보인다. 아직 계산을 안 한 상태이니까! 그래서 주소를 반환하는거다. 계산을 아직 안 해서 값이 없는 거다.

실제 계산이 들어가는 시점은, 이번 문제처럼 sum() 을 적용해서 실제로 값을 순회해야 하는 순간그때 비로소 계산하기 위해 값을 하나씩 꺼낸다. 아니면 list(map(int, '1234')) 이렇게 list() 함수에 감싸서 리스트로 강제 변환할 때는 map() 함수를 적용한 결과가 필요할 때이므로 그럴 때 계산을 시작한다.

 

또 중요한 점은, map 객체는 한 번 순회하면 다시 못 쓴다!

처음 list(result)에서 값을 꺼내면서 내부 데이터가 다 소모돼서, 두번째는 아무것도 안 나온다.
메모리 효율도 좋네...

 

미리 계산하지 않고 필요할 때 계산해서 쓰는 방식이 파이썬 만든 개발자들이 얼마나 최적화에 신경 썼는지 느끼게 해줬다. 대규모의 데이터를 들어오는 족족 함수에 적용하는게 아닌, 객체를 미리 만들어놓고 필요할 때 쓰면 더 빠르고 효율적으로 사용할 수 있다는 게 이해된다. 

똑똑한 사람들...

 

 

 

 

반응형

'코딩테스트' 카테고리의 다른 글

[백준] 15649 N과 M (1)  (0) 2025.04.23
[백준] 15650 N과 M (2)  (0) 2025.04.23
[백준] 1157 단어 공부  (0) 2025.04.18
[백준] 10798 세로 읽기  (0) 2025.04.18
[백준] 9046 복호화  (0) 2025.04.18