본문 바로가기

코틀린 Kotlin

Kotlin (3) - 코틀린의 repeat와 Pair를 알아보자 (백준 1003)

코틀린 3번째편 입니다.

코틀린을 코틀린 답게 쓰기 위해서 알고리즘 문제 위주로 알아가는중 입니다.

오늘 알아 볼것은 repeat 입니다. 

 

1. repact의 특징

https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/repeat.html

 

repeat - Kotlin Programming Language

 

kotlinlang.org

@kotlin.internal.InlineOnly
public inline fun repeat(times: Int, action: (Int) -> Unit) {
    contract { callsInPlace(action) }

    for (index in 0 until times) {
        action(index)
    }
}

repeat는 내부적으로 for문을 사용하는 inline 함수 입니다. 

내부적으로 for문을 사용하기 때문에 일반 반복문과 거의 흡사하지만

함수로 반복문을 사용하는 형태입니다.

사용 예시는 아래와 같습니다. 

repeat(5){ println(it)}

 

결과:0

      1

      2

      3 

      4 

첫번째 인자로 반복할 count를 받고 0부터 count의 횟수만큼 진행이 됩니다.

두번쨰 인자에서 고차함수의 패러미터로 돌고 있는 index를 전달합니다. 

 

주로 코틀린 for문에 익숙한 개발자가 실수 할 수 있는 부분이 있습니다.

첫번째 인자로 2를 준다면 인덱스가 2가 될때까지 반복하는걸로 착각 할 수 있습니다. 

해당 인덱스까지 반복문을 돌리는게 아니라 순수 반복할 count를 의미합니다. 

(repeat함수 내부 적으로 for(index in 0 until times) 이렇게 구현이 되어있음)

그러니 사용 할때 주의를 하시길 바랍니다. 

 

2.repeat의 장점? 

코틀린에서 for문은 for(i in 0..4){} 이런식으로 이렇게 표현이 되는 반면에

repeat는 함수형 언어의 특징을 살려서 반복문을 사용하기 때문에

반복문을 간결하고 심플하게 사용할 수 있는 것이 장점입니다.

코틀린 특징으로 람다형태로 코드를 쭉 읽어내려가기 편하고

for처럼 문 형식이 아니라서  for 문 만들때의 작은 실수 하는 경우는 repeat에서는 거의 없습니다.
ex: 사용하려는게 for(i in 0..4) 인데  for(i in 0 until 4) 로 잘못 적엇다던지..

 

(특히 index를 굳이 사용하지 않아도 되지만, 반복문을 써야하는 경우에 매우 편리 합니다.)

repeat(5){ 
 //내부에서 5번 횟수를 돈다.
}

 

 

3. Pair 특징

https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-pair/

 

Pair - Kotlin Programming Language

 

kotlinlang.org

public data class Pair<out A, out B>(
    public val first: A,
    public val second: B
) : Serializable {

    /**
     * Returns string representation of the [Pair] including its [first] and [second] values.
     */
    public override fun toString(): String = "($first, $second)"
}

페어는 data class 로 정의 되어있습니다. 제너릭을 통해서

2개의 인자 first, second를 받습니다. 

미리 정의한 pojo class 와 유사한 느낌이라고 보시면 됩니다. 

val test = Pair("first","second")
val list = listOf<Pair<String,String>>("test" to "test")

 

기본적으로 두개의 값을 동시에 가집니다.

first 혹은 second로 두개중에 자기가 원하는 value를 골라서 사용 할 수 있습니다.

    val test = Pair("first","second")
    val list = listOf("first" to "second")
    println(test.first)
    println(test.second)
    println(list.first().first)
    println(list.first().second)
    
//결과:first
//    second

 

4. Pair 장점

로직을 만들 때 한곳에서 2개의 value로 서로 비교를 하거나

두개의 value를 동시에 사용하는 경우 등등..

2개의 값을 가지고 활용하는데 좋은 용도로 사용이 됩니다. 

 

아래 알고리즘을 예시로 봐주세요

 

5. 사용해보기 

백준 1003 피보나치 함수 문제

 

https://www.acmicpc.net/problem/1003

 

1003번: 피보나치 함수

각 테스트 케이스마다 0이 출력되는 횟수와 1이 출력되는 횟수를 공백으로 구분해서 출력한다.

www.acmicpc.net

피보나치 함수(n) 일때 0과 1이 각각 몇번 출력되는지 알아보는 함수 입니다. 

보통의 경우 바로 재귀를 떠올리는 경우가 많지만 꼬리재귀가 아닌 일반적인 재귀함수를 사용하면 

많은 호출량으로 인해서 알고리즘상 시간이 너무 오래걸립니다.

 

이 문제는 Dp라는 동적 프로그래밍을 사용해서 풀어야하는 문제입니다. 

풀이는 아래와 같습니다.

 

 

백준 1003 풀이 

private fun dp1003() = with(BufferedReader(InputStreamReader(System.`in`))){
    val arr = Array(41) { 0 to 0 }.also {
        it[0] = 1 to 0
        it[1] = 0 to 1
    }
    repeat(arr.size) { pos ->
        if (pos > 1)
            arr[pos] = arr[pos - 1].first + arr[pos - 2].first to arr[pos - 1].second + arr[pos - 2].second
    }
    repeat(this.readLine().toInt()){
        val n = this.readLine().toInt()
        println("${arr[n].first} ${arr[n].second}")
    }
}

 

Pair와 repeat를 사용한 코드입니다. 

Pair배열을 만들어서 first에 0의 출력수 , second에 1의 출력수 각각 역활을 나눠둡니다. 

 

그다음 두번의 repeat사용 합니다.

첫번째 repeat는 pos-> 로 index를 사용합니다.

두번째 repeat는 인덱스를 사용하지 않고 반복을 위해 사용해줍니다. 

두번째 repeat 안에서 배열의 first, second를 출력해줍니다.

 

위와 같이 Pair와 repeat를 사용 할 수 있습니다.  이상 입니다.