조용한 담장

코틀린(Kotlin) Collections : Ranges and Progressions 본문

kotlin

코틀린(Kotlin) Collections : Ranges and Progressions

iosroid 2020. 1. 2. 18:25

코틀린(kotlin) collection 의 range(범위) and progression(수열) 에 대해 살펴보자.

원문 https://kotlinlang.org/docs/reference/ranges.html 을 보며 정리.

특정 범위의 값(range of values) 을 생성하는 방법에는 kotlin.ranges 패키지에 있는 rangeTo() 함수가 있으며 이 함수의 연산자 인 .. 를 사용한다.

operator fun <T : Comparable<T>> T.rangeTo(
    that: T
): ClosedRange<T>
operator fun Double.rangeTo(
    that: Double
): ClosedFloatingPointRange<Double>
operator fun Float.rangeTo(
    that: Float
): ClosedFloatingPointRange<Float>
val range = 1.0..100.0
println(range) // 1.0..100.0

println("3.14 in range is ${3.14 in range}") // true
println("100.1 in range is ${100.1 in range}") // false

보통 rangeTo() 는 in 또는 !in 함수와 함께 사용된다.

if (i in 1..4) {  // equivalent of 1 <= i && i <= 4
    print(i)
}

Integral type ranges (IntRange, LongRange, CharRange) 는 iteration 이 가능한 특징이 있다.

이것들은 각 대응되는 integral type 의 progression 이기도 하며 주로 for 문에서 iteration 을 위해 쓰인다.

class IntRange : IntProgression, ClosedRange<Int>
class LongRange : LongProgression, ClosedRange<Long>
class CharRange : CharProgression, ClosedRange<Char>
for (i in 1..4) print(i)

// output:
// 1234

반대의 순서로 하기 위해서는 downTo 함수를 사용한다.

for (i in 4 downTo 1) print(i)

// output:
// 4321

step 함수를 사용하면 증가 값을 지정할 수 있다.

for (i in 1..8 step 2) print(i)
println()
for (i in 8 downTo 1 step 2) print(i)

// output:
// 1357
// 8642

범위내에서 반복 범위를 제한하려면 until 함수를 사용한다.

for (i in 1 until 10) {       // i in [1, 10), 10 is excluded
    print(i)
}

// output:
// 123456789

Range

범위(range)는 순서(order)를 가지고, 두개의 주어진 인스턴스들 사이의 범위내에 있는 임의의 인스턴스인지 아닌지를 구분할 수 있는 comparable type 위해 정의된다.

범위와 관련된 주된 동작은 in!in 연산자의 형태로 사용되는 contains 이다.

내가 정의한 클래스를 위해 범위를 생성하기 위해서는 원하는 범위의 시작 값과 끝 값을 argument 로 가지는 rangeTo() 함수를 호출하면 된다.

rangeTo() 는 보통 .. 연산자 형태로 호출된다.

class Version(val major: Int, val minor: Int): Comparable<Version> {
    override fun compareTo(other: Version): Int {
        if (this.major != other.major) {
            return this.major - other.major
        }
        return this.minor - other.minor
    }
}

fun main() {
    val versionRange = Version(1, 11)..Version(1, 30)
    println(Version(0, 9) in versionRange)
    println(Version(1, 20) in versionRange)
}

// output:
// false
// true

Progression

위의 예제에서 보았듯이, Int, Long, Char 같은 integral types 의 범위들은 arithmetic progressions(등차수열) 로 취급될 수 있다.

코틀린 에서 이런 progression(수열) 은 IntProgression, LongProgression, CharProgression 와 같은 특별한 타입으로 정의된다.

open class IntProgression : Iterable<Int>
open class LongProgression : Iterable<Long>
open class CharProgression : Iterable<Char>

progression 은 first, last, non-zero step 를 기본 property 로 가진다.

첫번째 element 가 first 이며, 뒤에 따라오는 elements 는 이전 element 의 하나의 step 을 더한 값 이다.

마지막 element 는 항상 progression 가 비어있지 않다면 iteration 에 의해 접근 될 것이다.

progression 의 양의 값을 가지는 step 을 사용하는 iteration 은 자바와 자바스크립트의 indexed for loop 과 동등하다.

for (int i = first; i <= last; i += step) {
  // ...
}

range 의 iteration 을 통해서 progression 을 생성하는 경우에는 progression 의 first, 와 last element 는 range 의 endpoint 가 되고 step 은 1 이 된다.

for (i in 1..10) print(i)

// output:
// 12345678910

step 함수를 사용할 수 있다.

for (i in 1..8 step 2) print(i)

// output:
// 1357

progression 의 마지막 element 의 값은 양의 값을 가진 step 의 경우 최대값이 될것이고, 음의 값을 가진 step 의 경우 최소값이 될것이다.

(last-first) % step == 0

downTo 를 사용하여 역순으로 iteration 을 할 수 있다.

for (i in 4 downTo 1) print(i)

// output:
// 4321

progression 은 Int, Long, Char 각각의 타입의 NIterable<T> 을 구현하며, map 같은 다양한 collection functions 이나 filter 등에서 사용할 수 있다.

println((1..10).filter { it % 2 == 0 })

// output:
// [2, 4, 6, 8, 10]

 

Comments