본문 바로가기

코틀린

3장 - (아주 쉽게 설명한) 함수를 람다 식으로 변환해 봅시다(2/2).

앞에서 일반 함수를 람다 식으로 변환하는 방법을 설명했습니다. 함수 isPrime()은 어떤 숫자가 소수인지 여부를 판별합니다. 아래 코드는 isPrime()을 return 문을 사용하지 않는 람다 식(방법 2)으로 바꾼 것입니다.

val isPrimeLambda: (Int) -> Boolean =  { n: Int ->
    var status: Boolean = true
    for (i in 2..<n) {
        if (status && n % i == 0) {
            println("$n is a multiple of $i ")
            status = false
        }
    }
    status
}

위 코드를 아래처럼 확~  바꿀 수 있습니다. 코드가 이해되나요?

val isPrimeLambda : (Int)-> Boolean = { n: Int ->
    (n > 1) && (0 !in Array(n-2){ i -> n % (i+2)})
}

위 코드를 차근차근 분석해 볼까요? 람다 식 블록은 논리 AND 연산식이며, 연산 결과는 불린 값(true 또는 false) 입니다. 첫 번째 조건n > 1 입니다. 

(첫 번째 조건) && (두 번째 조건)  ->  (n > 1) && (두 번째 조건)

두 번째 조건을 살펴볼까요. 배열 객체를 생성하는 방법을 기억하고 있나요(262쪽, 5.1 배열). Array 생성자를 사용해 원소 갯수(=5)를 지정하고, 람다 식을 사용해 원소의 초깃값을 설정할 수 있습니다.

val n = 5
val ar: Array<Int> = Array (n) {  it  }
println(ar.contentToString())   // 0, 1, 2, 3, 4

Array(n-2)는 n이 5일때 1과 5를 제외한 3개의 원소를 갖는 배열을 만듭니다. 원소를 초기화할 때 n=5를 0+2(=2), 1+2(=3), 2+2(=4)로 각각 나눈 나머지를 배열 원소( [1, 2, 1] )로 초기화합니다.

Array (n-2) { n % (it+2) }   // 형식인자를 선언하는 대신 키워드 it를 사용
Array (n-2) { i: Int -> n % (i+2) }   // 1, 2, 1

배열 객체의 원소 중에 0이 있는지 검사하기 위해 in 연산자 또는 contains() 함수를 사용할 수 있습니다(106쪽, 2.6 범위 관련 연산). 0이 포함되어 있으면, 그 수로 나눌 수 있기 때문에 소수가 될 수 없습니다.  

(두 번째 조건) -> 0 !in Array( ... ) 
(두 번째 조건) -> ! Array( ... ).contains(0)

전체 코드를 보면서 앞에서 작성한 코드와 비교해보기 바랍니다. 코드가 훨씬 깔끔해졌죠! 이런 코딩 스타일이 MZ-세대 코딩입니다.

val isPrimeLambda: (Int) -> Boolean =  { n: Int ->
    n > 1 && 0 !in Array(n-2){ i: Int -> n % (i+2) }
    // n > 1 && !Array(n-2){ i: Int -> n % (i+2) }.contains(0)
}

fun main() {
    print("Enter integer value greater than 1 : ")
    val x = readln().toInt()

    val msg = "$x is a prime number."
    if (isPrimeLambda(x)) {
        println(msg)
    } else {
        println(msg.replace("is", "is not"))
    }
}