문제
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 |