例で理解するSequence<T>のfilterやmap

# はじめに

　Kotlinの[Sequence<T>](https://github.com/JetBrains/kotlin/blob/1.1.0/libraries/stdlib/src/kotlin/collections/Sequence.kt)は、次のような`Iterator<T>`を返す`iterator()`関数を持つインターフェースです。

```kotlin:
public interface Sequence<out T> {
    public operator fun iterator(): Iterator<T>
}
```

　[kotlin.sequences](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.sequences/-sequence/index.html)パッケージには、[Sequence<T>](https://github.com/JetBrains/kotlin/blob/1.1.0/libraries/stdlib/src/kotlin/collections/Sequence.kt)を生成する関数と多くの[Sequence<T>](https://github.com/JetBrains/kotlin/blob/1.1.0/libraries/stdlib/src/kotlin/collections/Sequence.kt)拡張関数が定義されています。拡張関数の中には[filter](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.sequences/filter.html)や[map](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.sequences/map.html)、[take](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.sequences/take.html)といった物があります。

　[List<T>](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-list/index.html)にも[map](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/map.html)や[filter](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/filter.html)、[take](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/take.html)がありますね。

　この投稿では、List<T>のmapやfilter、takeとの違いを通して、Sequence<T>のmapとfilter、takeの挙動を紹介します。

# `List<T>`のfilter・map・take

　[List<T>](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-list/index.html)の[filter](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/filter.html)、[map](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/map.html)、[take](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/take.html)の挙動を見てみましょう。

　filterは選択を、mapは射影を行う関数です。takeは先頭から指定した要素数の`List<T>`を新たに生成する関数です。

　実際のコードではfilterやmapに渡す関数リテラル内部で副作用のある`println`を行うことは良くありません。今回は挙動を紹介するために関数リテラル内でprintlnを使います。


```kotlin:List<T>のfilter・mapの例
    val list : List<Int> = listOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
    val converted : List<String> = list
            .filter { // 偶数だけに選択
                println("filter $it")
                it.rem(2) == 0
            }
            .map { // 文字列型に射影
                println("map $it")
                it.toString()
            }
            .take(3) // 戦闘から3個だけのList<T>に

    println("--------")

    for(it in converted) println("for $it")
```

　上のコードの実行結果は次の通りです。

```
filter 0
filter 1
filter 2
filter 3
filter 4
filter 5
filter 6
filter 7
filter 8
filter 9
map 0
map 2
map 4
map 6
map 8
--------
for 0
for 2
for 4
```

　まず、filterが実行されます。すべての要素に対してfilterに渡した関数リテラルが適用されていますね。

　次に、mapが実行されます。filterした結果のList<Int>にmapに渡した関数リテラルが適用されていますね。

　そして、takeが実行されます。しかし特に何も表示されません。

　そしてfor文の前のprintlnが実行され、`--------`が表示されています。

　最後にfor文が実行されます。

　`List<T>`のfilterはその場で全要素を選択し、mapはその場で全要素を射影します。


# `Sequence<T>`のfilter・map・take

　それでは同様のコードの`Sequence<T>`版を見てみましょう。

```kotlin
    val list : Sequence<Int> = sequenceOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
    val converted : Sequence<String> = list
            .filter {
                println("filter $it")
                it.rem(2) == 0
            }
            .map {
                println("map $it")
                it.toString()
            }
            .take(3)

    println("--------")

    for(it in converted) println("for $it")
```

　実行結果は次の通りです。


```
--------
filter 0
map 0
for 0
filter 1
filter 2
map 2
for 2
filter 3
filter 4
map 4
for 4
```

　List<T>のfilter・map・takeとの実行結果と大きく違うことに気が付きましたか？

　`--------`がまず表示されていますね。表示された結果から、filterやmapに渡した関数リテラルの適用は`--------`を表示された後にされていますね。

　`Sequence<T>`のfilter・map・takeは、すべての要素に対して一気に行われるわけではありません。その要素が必要になったタイミングで実行されるのです。

　それでは、見ていきましょう。

　まず、filterが実行されます。しかし特に表示はされていません。各要素に対しての選択はまだ実行されていません。

　次に、mapが実行されます。しかし特に表示はされていません。各要素に対しての射影はまだ実行されていません。

　そして、takeが実行されます。しかし特に表示はされません。

　そしてfor文の前のprintlnが実行され、`--------`が表示されています。

　最後にfor文が実行されます。

　for文で要素の列挙を始められ、要素が必要になります。そして先頭からfilter・map・takeが実行されます。

# まとめ

　`List<T>`のmapやfilterはその場で全要素を射影・選択が実行されます。

　それとは異なり、`Sequence<T>`のmapやfilterは要素が必要になったタイミングで、必要な分の要素に対して射影の処理・選択の処理が行われます。