오늘은 알고리즘 문제와 함께 코틀린의 기초 문법에 대해 살펴보았다.
첫 문제는 num1을 num2로 나눈 값에 1,000을 곱한 후 정수 부분을 반환하는 함수를 작성해야했다.
처음엔 단순히 문제에 나온 순서 그대로 num1 / num2 * 1000
으로 제출했었는데, 코틀린은 정수를 정수로 나누게 될 경우 소수점을 버린 정수로 계산이 되어 오답이라는 것이다. 그래서 이후에는 형변환을 사용해 다음과 같은 답을 제출했다.
fun solution(num1: Int, num2: Int): Int {
var answer = num1 / num2.toDouble() * 1000 // 실수로 형변환
return answer.toInt() // 정수로 형변환
}
정답이었지만 뭔가… 코드가 길어지니까 마음에 들지 않았다. 더 좋은 방법이 없나 싶었는데, 다른 사람의 풀이 중 단순히 계산 순서를 바꿔 num1 * 1000 / num2
로 계산하신 분이 있었다. 이걸 보고 정말 세상에 똑똑한 사람은 많고 나는 더 많이 정진해야겠다는 생각이 들었다.
다음으로는 주어진 각이 어떤 각인지 1~4의 숫자로 리턴하면되는 문제여서, 조건문을 이용해 풀이했다.
fun solution(angle: Int): Int {
if (angle < 90) return 1
else if (angle == 90) return 2
else if (angle < 180) return 3
else return 4
}
비교연산자를 통해 조건을 작성했는데, in
과 until
, ..
을 사용한 풀이가 대부분이었다. 모르는 게 나왔다면 알아봐야지. 이게 대체 뭐길래 다들 쓰는걸까.
num in 1 until 90
num in 1..89
위의 두 문장은 같은 범위(1 ~ 89)를 표현한다. 차이점을 정리하자면 다음과 같다.
until
: 마지막 값 포함 X..
: 마지막 값 포함 O혹시 다른 범위 표현식은 없을까?
코틀린과 아직 잘 아는 사이가 아니라 하나부터 열까지 꼭꼭 씹어 물어보는 중이다. step
과 downTo
라는 아이들도 있는 모양이다. step
의 경우 수열의 증가 혹은 감소 폭을 지정해준다고 한다.
num in 1..10 step 3
// 1 부터 10까지 3씩 증가한다. 1, 4, 7, 10
num in 10 downTo 1
// 10 부터 1까지 1씩 감소한다. (..과 방향만 다르다)
num in 10 downTo 1 step 3
// 10 부터 1까지 3씩 감소한다. 10, 7, 4, 1
알게되었다면 적용해보는 것이 인 지 상 정. 배운 것을 이용해 다시 한 번 풀어보자.
fun solution(angle: Int): Int {
if (angle in 1..89) return 1
if (angle == 90) return 2
if (angle in 91 until 180) return 3
else return 4
}
앗 그런데 if else
말고 다른 방법은 없는 걸까? switch case
문 같은걸 사용하면 더 간단해질 것 같은데..라는 생각에 코틀린의 switch case
문을 찾아보았다.
코틀린에는 switch case
문의 역할을 하는 when
구문이 있다고 한다. 사용법을 간단하게 살펴보자면,
when (변수) {
값 -> 코드
값 -> 코드
...
else -> 코드
}
가 되겠다. 화살표를 사용하는 게 인상깊었다. 게다가 상수만을 조건으로 줄 수 있는 switch case
문과 다르게 “값” 부분에 “조건식”도 들어갈 수 있다고 한다! 아주 기똥찬 자식이다. 자, 이제 다시 적용해보자.
fun solution(angle: Int): Int {
when (angle) {
in 1..89 -> return 1
90 -> return 2
in 91 until 180 -> return 3
else -> return 4
}
}
조건식으로 ..과 until을 사용할 때 in도 같이 써주는 걸 잊지 말자.. 빼먹었다가 에러를 마주하게 될 수 있다. (경험담 아님)
이번에는 1부터 n까지의 숫자 중 짝수만 더하면 되는 문제였다. 수학 공식을 이용하면 수식 한 줄로 가능한 문제라는 생각이 들어 다음과 같이 풀이했다.
fun solution(n: Int): Int {
var num = n / 2
return num * (1 + num)
}
이용한 공식은 다음과 같다.
그러다 문득 든 생각은, 어라 코틀린을 알아가려고 알고리즘 문제를 푸는건데 수학 문제 풀듯이 풀이하는게 맞나? 였다. 문제의 원래 의도는 (아마) 반복문과 조건문에 좀 더 익숙해지라고 낸 듯 싶었다. 그래서! 의도대로 코틀린의 반목문을 알아보았다.
보통 반복을 할 때, for
문과 while
문을 많이 사용한다. 나 같은 경우는 특정 횟수만큼의 반복에는 for
문을, 특정 조건에서만 반복에는 while
문을 사용하는 편이다.
for (i: Int in 1..10) {
...
}
in
뒤에 범위 표현식 말고도 배열이나 컬렉션을 사용할 수 있다고 한다. 배열을 돌 때 자주 사용될 것 같은 녀석이다.
while (i > 0) {
...
}
do {
...
} while (i > 0)
while
문은 한 번도 실행되지 않을 수 있지만, do while
문은 최소 한 번의 실행을 보장한다. 내가 까먹을까봐 적어놓겠다. 다행히 while
문은 다른 언어들과 비슷한 것 같다.
이제 다시 문제로 돌아와서, 반복문과 조건문을 사용해 풀이해보자!
fun solution(n: Int): Int {
var answer: Int = 0
for (i: Int in 1..n) {
if (i % 2 == 0) answer += i
}
return answer
}
여기서 우리는 또 한 번 의문을 가지게 된다. (아님 말고..) 아 짝수만 골라내서 sum()
함수를 사용하면 될 텐데.. 코틀린에는 map
이나 filter
같은 게 없는걸까?
역시 있었다. filter는 조건에 맞는 원소만을 필터링해준다. 사용은 다음과 같이 한다고 한다.
(컬렉션 또는 배열).filter { 조건 }
이걸 풀이에 적용해보면,
(1..n).filter { num -> num % 2 == 0 }.sum()
// 1..10 은 1부터 10까지의 범위를 생성해준다. [1, 2, ..., n]
// filter 를 통해 짝수만 필터링한다. [2, 4, ..., n]
// sum 으로 필터링 된 범위 전부를 합한다.
// num -> 은 it 표기법을 사용해 생략이 가능하다.
(1..n).filter { it % 2 == 0 }.sum()
주석 중에 it
표기법에 대해 추가적으로 설명하자면, 람다식 내부에서 사용되는 암시적 변수로 인자가 하나인 경우에 it
키워드를 사용해 참조할 수 있다. 람다식은 나중에 더 알아보도록 하자. 아직 다루기엔 너무 이른 것 같다.
아주 약간의 (사실 많이..) 배신감을 느꼈던 문제가 있다. 정수 배열의 평균을 구하는 문제였는데, 당연히 배열을 전부 더해 배열의 길이로 나누는 방식으로 풀이를 했었다. 풀고나서 다음과 같은 코드를 봤을 때 나의 무지함에 서운함과 통탄스러움을 감출 수 없었다.
numbers.average()
참고로 나의 풀이는 다음과 같았다.
numbers.sum()*1.0/numbers.size
// 1.0(Double형)을 곱해 형변환을 해주었다.
average
.. 오늘이라도 안 것에 기뻐하는 중이다. 다음엔 꼭 잊지않고 써먹는 날이 올 것이다.