λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°

빈 ꡬ멍 μ±„μš°κΈ°

[Kotlin] Sequence

interface Sequence<out T>

μ‹œν€€μŠ€μ˜ iteratorλ₯Ό 톡해 값듀을 λ°˜ν™˜ν•œλ‹€. 값듀은 lazily ν•˜κ²Œ κ³„μ‚°λ˜κ³ , μ‹œν€€μŠ€λŠ” 잠재적으둜 λ¬΄ν•œν•˜κ²Œ 값을 넣을 수 μžˆλ‹€.

μ‹œν€€μŠ€λŠ” μ—¬λŸ¬λ²ˆ λ°˜λ³΅λ  μˆ˜ μžˆμ§€λ§Œ λͺ‡λͺ‡ μ‹œν€€μŠ€ κ΅¬ν˜„듀은 ν•œ λ²ˆλ§Œ λ°˜λ³΅λ˜λ„둝 μ œμ–΄ν•œλ‹€. ν›„μžμ˜ μ‹œν€€μŠ€λŠ” λ‘ λ²ˆ λ°˜λ³΅μ„ μ‹œλ„ν•  λ•Œ exception을 λ°œμƒμ‹œν‚¨λ‹€.

 

interface Iterable<out T>

Iterable μΈν„°νŽ˜μ΄μŠ€λ₯Ό μƒμ†ν•˜λŠ” ν΄λž˜μŠ€λ“€μ€ λ°˜λ³΅ κ°€λŠ₯ν•œ μΌλ ¨μ˜ μš”μ†Œλ“€λ‘œμ„œ ν‘œν˜„될 μˆ˜ μžˆλ‹€.

 

kotlinlang.org/docs/sequences.html#from-a-function

 

Sequences - Help | Kotlin

 

kotlinlang.org

kotlinlang.org/api/latest/jvm/stdlib/kotlin.sequences/-sequence/

 

Sequence - Kotlin Programming Language

 

kotlinlang.org

 

collenctions와 ν•¨κ»˜, μ½”ν‹€λ¦° standard libraryλŠ” sequence(Sequence <T>)λΌλŠ” 또 λ‹€λ₯Έ container νƒ€μž…μ„ 가지고 μžˆλ‹€.

μ‹œν€€μŠ€λŠ” Iterableκ³Ό 같은 ν•¨μˆ˜λ“€μ„ μ œκ³΅ν•˜λ‚˜, multi-step collection(닀단계 μˆ˜μ§‘) μ²˜λ¦¬μ— 또 λ‹€λ₯Έ 접근방법을 κ΅¬ν˜„ν•œλ‹€.

 

Iterable의 μ²˜λ¦¬λŠ” μ—¬λŸ¬ λ‹¨κ³„듀을 ν¬ν•¨ν•  λ•Œ, κ·Έ λ‹¨κ³„듀은 μ—΄μ‹¬νžˆ μ²˜λ¦¬λœλ‹€. κ° μ²˜λ¦¬ λ‹¨κ³„κ°€ μ™„λ£Œν•˜κ³  μ€‘κ°„ μ»¬λ ‰μ…˜μΈ κ²°κ³Όλ₯Ό λ°˜ν™˜ν•œλ‹€. λ‹€μŒ λ‹¨κ³„λŠ” μ΄ μ€‘κ°„ μ»¬λ ‰μ…˜μ„ μˆ˜ν–‰ν•œλ‹€. μ‹œν€€μŠ€μ˜ μ—¬λŸ¬ λ‹¨κ³„ μ²˜λ¦¬λŠ” κ°€λŠ₯ν•  λ•Œ κ²ŒμœΌλ₯΄κ²Œ μ‹€ν–‰λœλ‹€. μ‹€μ œ κ³„산은 μ „체 ν”„λ‘œμ„ΈμŠ€ μ²΄μΈμ˜ κ²°κ³Όκ°€ μš”청될 λ•Œμ—λ§Œ μΌμ–΄λ‚œλ‹€. 

μ—°μ‚° μ‹€ν–‰ μˆœμ„œλ„ λ‹€λ₯΄λ‹€. SequenceλŠ” λͺ¨λ“  ν•˜λ‚˜μ˜ μš”μ†Œλ§ˆλ‹€ λͺ¨λ“  μ²˜λ¦¬ λ‹¨κ³„λ₯Ό ν•œ λ‹¨κ³„μ”© μˆ˜ν–‰ν•˜κ³ , Iterable은 μ „체 collection의 κ° λ‹¨κ³„λ₯Ό μ™„λ£Œν•˜κ³  λ‹€μŒ λ‹¨κ³„λ‘œ μ§„ν–‰ν•œλ‹€.

κ·Έλž˜μ„œ μ‹œν€€μŠ€λŠ” μ€‘κ°„ λ‹¨κ³„μ˜ κ²°κ³Όλ¬Ό μƒμ„±μ„ ν”Όν•˜κΈ° λ•Œλ¬Έμ— μ „체 μ½œλ ‰μ…˜ μ²˜λ¦¬ μ²΄μΈμ˜ μ„±λŠ₯을 μ¦κ°€μ‹œν‚¨λ‹€.
κ·ΈλŸ¬λ‚˜ μ‹œν€€μŠ€μ˜ κ²ŒμœΌλ₯΄λ‹€λŠ” νŠΉμ„±μ΄ λ” μž‘은 μ½œλ ‰μ…˜μ„ μ²˜λ¦¬ν•˜κ±°λ‚˜ λ” κ°„λ‹¨ν•œ κ³„산을 ν•  λ•Œ μƒλ‹Ήν•œ μ˜€λ²„ν—€λ“œλ₯Ό λ§Œλ“ λ‹€. 
λ”°λΌμ„œ Sequence와 Iterable을 λ™μ‹œμ— κ³ λ €ν•΄ μƒν™©μ— λ”°λΌ μ–΄λŠ κ²ƒμ΄ λ” λ‚˜μ€μ§€ κ²°μ •ν•΄μ•Ό ν•œλ‹€.

 

생성

μš”μ†Œλ“€λ‘œ

sequnceOf() ν•¨μˆ˜λ‘œ μš”μ†Œλ“€μ„ λ§€κ°œλ³€μˆ˜λ“€λ‘œ λ‚˜μ—΄ν•œλ‹€.

val numbersSequence = sequenceOf("four", "three", "two", "one")

fun <T> sequenceOf(vararg elements: T): Sequence<T>

μ§€μ •λœ 값을 λ°˜ν™˜ν•˜λŠ” μ‹œν€€μŠ€λ₯Ό μƒμ„±ν•œλ‹€.

Iterable둜 

이미 Iterable κ°μ²΄(List, Set λ“±)λ₯Ό κ°€μ§€κ³  μžˆλ‹€λ©΄ asSequence()λ₯Ό ν˜ΈμΆœν•œλ‹€.

val numbers = listOf("one", "two", "three", "four")
val numbersSequence = numbers.asSequence()

asSequence

fun <T>  Array<out T>.asSequence(): Sequence<T>

fun ByteArray.asSequence(): Sequence<Byte>

fun ShortArray.asSequence(): Sequence<Short>

fun IntArray.asSequence(): Sequence<Int>

fun LongArray.asSequence(): Sequence<Long>

fun FloatArray.asSequence(): Sequence<Float>

fun DoubleArray.asSequence(): Sequence<Double>

fun BooleanArray.asSequence(): Sequence<Boolean>

fun CharArray.asSequence(): Sequence<Char>

fun <T> Iterable<T>.asSequence(): Sequence<T>

fun <K, V> Map<out K, V>.asSequence(): Sequence<Entry<K, V>>

ν•¨μˆ˜λ‘œ

generateSequnce()λ₯Ό ν˜ΈμΆœν•΄ ν•¨μˆ˜μ— κΈ°λ°˜ν•œ μ‹œν€€μŠ€λ₯Ό μƒμ„±ν•œλ‹€. λ§€κ°œλ³€μˆ˜λ‘œ ν•¨μˆ˜λ₯Ό λ„£λŠ”λ‹€. μ„ νƒμ μœΌλ‘œ, 첫 μš”μ†ŒλŠ” λͺ…μ‹œμ μΈ κ°’μ΄λ‚˜ ν•¨μˆ˜ 호좜 결과둜 지정할 수 μžˆλ‹€. 제곡된 ν•¨μˆ˜κ°€ null을 리턴할 λ•Œ μ‹œν€€μŠ€ 생성이 μ€‘μ§€λœλ‹€. 

 

generateSequence

 

fun <T: Any> getnerateSequence(

    nextFunction: () -> T?

): Sequence<T>

nextFunction이 null을 λ°˜ν™˜ν•  λ•ŒκΉŒμ§€ 각 iterationμ—μ„œ λ‹€μŒ 값을 κ³„μ‚°ν•˜λŠ” nextFunction을 ν˜ΈμΆœν•˜λŠ” μ‹œν€€μŠ€λ₯Ό λ°˜ν™˜ν•œλ‹€.

 

fun <T: Any> generateSequence(

    seed: T?,

    nextFunction: (T) -> T?

): Sequence<T>

seed 값을 μ‹œμž‘ nextFunction ν•¨μˆ˜μ˜ μ‹œμž‘ν•˜λŠ” κ°’μœΌλ‘œ μ •μ˜ν•˜κ³ , nextFunction이 null을 λ°˜ν™˜ν•  λ•ŒκΉŒμ§€ 각 iterationμ—μ„œ λ‹€μŒ 값을 κ³„μ‚°ν•˜λŠ” nextFunction을 ν˜ΈμΆœν•˜λŠ” μ‹œν€€μŠ€λ₯Ό λ°˜ν™˜ν•œλ‹€.

 

fun <T: Any> generateSequence(

    seedFunction: () -> T?,

    nextFunction: () -> T?

): Sequence<T>

 

 

μ•„λž˜ 예제의 μ‹œν€€μŠ€λŠ” λ¬΄ν•œλŒ€μ΄λ‹€.

fun main() {
    val oddNumbers = generateSequence(1) { it + 2 } // `it` is the previous element
    println(oddNumbers.take(5).toList())
    //println(oddNumbers.count())     // error: the sequence is infinite
}

κ²°κ³Ό

[1, 3, 5, 7, 9]

μœ ν•œν•œ μ‹œν€€μŠ€λ₯Ό generateSequence()둜 μƒμ„±ν•˜κΈ° μœ„ν•΄μ„œλŠ” μ œκ³΅ν•˜λŠ” ν•¨μˆ˜κ°€ λ§ˆμ§€λ§‰ μš”μ†Œ 뒀에 null을 λ°˜ν™˜ν•˜λ„λ‘ ν•œλ‹€.

fun main() {
    val oddNumbersLessThan10 = generateSequence(1) { if (it < 8) it + 2 else null }
    println(oddNumbersLessThan10.count())
}

κ²°κ³Ό

5

chunck둜

sequence() ν•¨μˆ˜λ‘œ μž„μ˜μ˜ 크기의 chunck(덩어리)듀을 μš”μ†Œ ν•˜λ‚˜μ”© μ‹œν€€μŠ€ μš”μ†Œλ‘œ 생성할 수 μžˆλ‹€. 이 ν•¨μˆ˜λŠ” yield()와 yieldAll() ν•¨μˆ˜λ“€μ„ ν¬ν•¨ν•˜λŠ” λžŒλ‹€ ν‘œν˜„μ‹μ„ μ‚¬μš©ν•œλ‹€. 이 yield()와 yieldAll()은 μ‹œν€€μŠ€ consumer에 μš”μ†Œλ₯Ό λ°˜ν™˜ν•˜κ³  consumerκ°€ λ‹€μŒ μš”μ†Œλ₯Ό μš”μ²­ν•  λ•ŒκΉŒμ§€ sequence() 싀행을 μ€‘λ‹¨ν•œλ‹€. yield()λŠ” λ§€κ°œλ³€μˆ˜λ₯Ό ν•˜λ‚˜λ§Œ μ“΄λ‹€. yieldAll()은 Iterable 객체, Iterator, μ•„λ‹ˆλ©΄ λ‹€λ₯Έ μ‹œν€€μŠ€λ₯Ό  λ§€κ°œλ³€μˆ˜λ‘œ μ“΄λ‹€. yieldAll()의 μ‹œν€€μŠ€ λ§€κ°œλ³€μˆ˜λŠ” λ¬΄ν•œν•  수 μžˆλ‹€. κ·ΈλŸ¬λ‚˜ 이런 ν˜ΈμΆœμ€ 맨 λ§ˆμ§€λ§‰ μˆœμ„œμ—¬μ•Ό ν•œλ‹€. λ‹€λ₯Έ 후속 ν˜ΈμΆœλ“€μ΄ μ‹€ν–‰λ˜μ§€ μ•Šμ„ 수 있기 λ•Œλ¬Έμ΄λ‹€.

 

fun main() {
    val oddNumbers = sequence {
        yield(1)
        yieldAll(listOf(3, 5))
        yieldAll(generateSequence(7) { it + 2 })
    }
    println(oddNumbers.take(5).toList())
}

κ²°κ³Ό

[1, 3, 5, 7, 9]

 

kotlin-stdlib/kotlin.sequences/SequenceScope

 

abstract suspend fun yield(value:T)

생성쀑인(being built) Iterator에 valueλ₯Ό μ œκ³΅ν•˜κ³  λ‹€μŒ valueκ°€ μš”μ²­λ  λ•ŒκΉŒμ§€ μΌμ‹œ μ€‘λ‹¨ν•œλ‹€.

 

abstract suspend fun yieldAll(iterator: Iterator<T>)

 iteratorλ‘œλΆ€ν„° λͺ¨λ“  값듀이 반볡되고 λ‹€μŒ 값이 μš”μ²­λ  λ•ŒκΉŒμ§€ μƒμ„±λ˜κ³  쀑단할 Iterator둜 λͺ¨λ“  값듀을 μ‚°μΆœν•œλ‹€.

suspend fun yieldAll(element: Iterable<T>)

iteratorλ‘œλΆ€ν„° λͺ¨λ“  값듀이 반볡되고 λ‹€μŒ 값이 μš”μ²­λ  λ•ŒκΉŒμ§€ μƒμ„±λ˜κ³  쀑단할 Iterator둜 κ°’λ“€μ˜ collection ν•˜λ‚˜λ₯Ό μ‚°μΆœν•œλ‹€.

suspend fun yieldAll(sequence: Sequence<T>)

iteratorλ‘œλΆ€ν„° λͺ¨λ“  값듀이 반볡되고 λ‹€μŒ 값이 μš”μ²­λ  λ•ŒκΉŒμ§€ μƒμ„±λ˜κ³  쀑단할 Iterator둜 값듀이 λ¬΄ν•œλŒ€μΌ 수 μžˆλŠ” μ‹œν€€μŠ€λ₯Ό μ‚°μΆœν•œλ‹€.

 

 

μ‹œν€€μŠ€ μž‘μ—…

μ‹œν€€μŠ€ μ—°μ‚°(μž‘μ—…)은 μƒνƒœ μš”κ΅¬μ‚¬ν•­μ— 따라 μ•„λž˜μ˜ κ·Έλ£Ήλ“€λ‘œ λΆ„λ₯˜ν•  수 μžˆλ‹€.

  • Stateless 연산듀은 μƒνƒœλ₯Ό ν•„μš”λ‘œ ν•˜μ§€ μ•Šκ³  각 elementλ₯Ό λ…λ¦½μ μœΌλ‘œ μ²˜λ¦¬ν•˜λŠ”λ°, 예λ₯Ό λ“€μ–΄μ„œ, map() λ˜λŠ” filter()κ°€ μžˆλ‹€. Stateless 연산듀이 elementλ₯Ό μ²˜λ¦¬ν•˜λŠ”λ° μΌμ •λŸ‰μ˜ stateκ°€ ν•„μš”ν•  μˆ˜λ„ μžˆλ‹€. 예λ₯Ό λ“€λ©΄ take(), drop()이 μžˆλ‹€.
  • State 연산듀은 μƒλ‹ΉλŸ‰μ˜ μƒνƒœλ₯Ό μš”κ΅¬ν•˜λŠ”λ°, λŒ€κ°œ μ‹œν€€μŠ€μ˜ element의 μˆ˜μ— λΉ„λ‘€ν•œλ‹€.

λ§Œμ•½ μ‹œν€€μŠ€ 연산이 λ‹€λ₯Έ μ‹œν€€μŠ€λ₯Ό lazily ν•˜κ²Œ 생성해 λ°˜ν™˜ν•˜λ‹€λ©΄, intermediate라고 λΆˆλ¦°λ‹€. λ‹€λ₯Έ κ²½μš°μ— 이 연산은 terminal이닀. terminal μ—°μ‚°μ˜ μ˜ˆλ‘œλŠ” toList()와 sum()이 μžˆλ‹€. μ‹œν€€μŠ€ μš”μ†Œλ“€μ€ terminal μ—°μ‚¬λ“€μ—μ„œλ§Œ λ°›μ•„μ˜¬ 수 μžˆλ‹€.

 

μ‹œν€€μŠ€λ“€μ€ μ—¬λŸ¬ 번 반볡될 수 μžˆμœΌλ‚˜ λͺ‡λͺ‡ μ‹œν€€μŠ€ κ΅¬ν˜„λ“€μ€ ν•œ 번만 λ°˜λ³΅λ˜λ„λ‘ μ œν•œν•œλ‹€. 

 

Iterable

단어 리슀트λ₯Ό 가지고 μžˆλ‹€κ³  ν•΄λ³΄μž. μ•„λž˜μ˜ μ½”λ“œλŠ” κΈ€μž μˆ˜κ°€ 3을 λ„˜μœΌλ©΄ 단어λ₯Ό ν•„ν„°λ§ν•˜κ³  ν•„ν„°λ§λœ λ‹¨μ–΄μ˜ 첫 4개만 길이λ₯Ό 좜λ ₯ν•œλ‹€.

fun main() {    
    val words = "The quick brown fox jumps over the lazy dog".split(" ")
    val lengthsList = words.filter { println("filter: $it"); it.length > 3 }
        .map { println("length: ${it.length}"); it.length }
        .take(4)

    println("Lengths of first 4 words longer than 3 chars:")
    println(lengthsList)
}

κ²°κ³Ό

filter: The
filter: quick
filter: brown
filter: fox
filter: jumps
filter: over
filter: the
filter: lazy
filter: dog
length: 5
length: 5
length: 5
length: 4
length: 4
Lengths of first 4 words longer than 3 chars:
[5, 5, 5, 4]

 

이 μ½”λ“œλ₯Ό μ‹€ν–‰ν•  λ•Œ, filter()와 map() ν•¨μˆ˜κ°€ μ½”λ“œμ—μ„œ λ‚˜νƒ€λ‚œ μˆœμ„œλŒ€λ‘œ μ‹€ν–‰λ˜λŠ” 것을 λ³Ό 수 μžˆλ‹€. μ²˜μŒμ—, λͺ¨λ“  μš”μ†Œλ“€μ΄ filterλ₯Ό 거치고, 필터링을 거친 단어듀이 lengthλ₯Ό μ§€λ‚˜, λ§ˆμ§€λ§‰ 두 μ€„μ˜ 좜λ ₯이 λ‚˜μ˜¨λ‹€.

 

λ¦¬μŠ€νŠΈκ°€ μ–΄λ–»κ²Œ μ²˜λ¦¬λ˜λŠ”μ§€λŠ” λ‹€μŒκ³Ό κ°™λ‹€.

https://kotlinlang.org/docs/sequences.html#sequence

Sequence

μ‹œν€€μŠ€λ‘œ λ˜‘κ°™μ΄ μž‘μ„±ν•  수 μžˆλ‹€.

fun main() {
    val words = "The quick brown fox jumps over the lazy dog".split(" ")
    //convert the List to a Sequence
    val wordsSequence = words.asSequence()

    val lengthsSequence = wordsSequence.filter { println("filter: $it"); it.length > 3 }
        .map { println("length: ${it.length}"); it.length }
        .take(4)

    println("Lengths of first 4 words longer than 3 chars")
    // terminal operation: obtaining the result as a List
    println(lengthsSequence.toList())
}

κ²°κ³Ό

Lengths of first 4 words longer than 3 chars
filter: The
filter: quick
length: 5
filter: brown
length: 5
filter: fox
filter: jumps
length: 5
filter: over
length: 4
[5, 5, 5, 4]

이 μ½”λ“œμ˜ 아웃풋은 κ²°κ³Ό λ¦¬μŠ€νŠΈκ°€ λ§Œλ“€μ–΄μ§ˆ λ•Œ filter()와 map() ν•¨μˆ˜κ°€ ν˜ΈμΆœλ˜λŠ” 것을 보여쀀닀. κ·Έλž˜μ„œ "Length of..." λ¬Έμž₯을 제일 λ¨Όμ € λ³Ό 수 μžˆλŠ” 것이고, μ‹œν€€μŠ€ μ²˜λ¦¬κ°€ κ·Έ 후에 μ§„ν–‰λœλ‹€. 필터링을 ν†΅κ³Όν•œ μš”μ†Œλ“€μ— λŒ€ν•΄μ„œλŠ”, λ‹€μŒ μš”μ†Œλ₯Ό ν•„ν„°λ§ν•˜κΈ° 전에 map이 μ‹€ν–‰ν•œλ‹€. κ²°κ³Ό 크기가 4에 도달할 λ•Œ, 처리 과정은 λ©ˆμΆ”λŠ”λ°, take(4)κ°€ λ°˜ν™˜ν•  수 μžˆλŠ” κ°€λŠ₯ν•œ κ°€μž₯ 큰 μ‚¬μ΄μ¦ˆμ΄κΈ° λ•Œλ¬Έμ΄λ‹€.

μ‹œν€€μŠ€ 처리 과정은 λ‹€μŒκ³Ό 같이 λœλ‹€.

https://kotlinlang.org/docs/sequences.html#sequence

이 μ˜ˆμ œμ—μ„œ, μ‹œν€€μŠ€ μ²˜λ¦¬λŠ” 리슀트둜 같은 μž‘μ—…μ„ 23 λ‹¨κ³„λ‘œ μ²˜λ¦¬ν•˜λŠ” 것 λŒ€μ‹  18단계λ₯Ό 가진닀.