Caution

お使いのブラウザはJavaScriptが実行できない状態になっております。
当サイトはWebプログラミングの情報サイトの為、
JavaScriptが実行できない環境では正しいコンテンツが提供出来ません。
JavaScriptが実行可能な状態でご閲覧頂くようお願い申し上げます。

Kotlin辞典

  1. トップページ
  2. Kotlin辞典
  3. sequenceOf() / generateSequence()

sequenceOf() / generateSequence()

Kotlinの『Sequence』は遅延評価(lazy evaluation)のコレクションです。『sequenceOf()』や『generateSequence()』で作成でき、『asSequence()』で既存コレクションを変換できます。中間処理は終端操作が呼ばれるまで実行されません。

構文
// sequenceOf — 固定要素のシーケンス
val seq = sequenceOf(1, 2, 3, 4, 5)

// generateSequence — 無限シーケンス(終端操作で必ず制限します)
val naturals = generateSequence(1) { it + 1 }  // 1, 2, 3, ...
val first10 = naturals.take(10).toList()

// asSequence — リストをシーケンスに変換します。
val list = listOf(1..100)
val result = list.asSequence()
    .filter { it % 2 == 0 }
    .map { it * it }
    .take(5)
    .toList()  // 終端操作で実行されます。

// sequence ビルダー
val fib = sequence {
    var a = 0; var b = 1
    while (true) { yield(a); val t = a + b; a = b; b = t }
}
メソッド一覧
メソッド/関数概要
sequenceOf(要素...)固定要素のシーケンスを作成します。
generateSequence(初期値) { 次の値 }関数で次の値を生成する(無限)シーケンスを作成します。null を返すと終了します。
generateSequence { 値 or null }シードなしで generateSequence します。
sequence { yield(値) }コルーチンビルダーで複雑なシーケンスを定義します。
コレクション.asSequence()既存コレクションをシーケンスに変換します。
シーケンス.take(n)先頭 n 件だけを取り出します(中間操作)。
シーケンス.filter { }遅延評価でフィルタリングします(中間操作)。
シーケンス.map { }遅延評価で変換します(中間操作)。
シーケンス.toList()終端操作 — シーケンスを評価してリストに変換します。
サンプルコード
fun main() {
    // sequenceOf — 固定要素
    val seq = sequenceOf("A", "B", "C")
    seq.forEach { print("$it ") }
    println()

    // generateSequence — 自然数の無限シーケンス
    val naturals = generateSequence(1) { it + 1 }
    println("最初の10個: ${naturals.take(10).toList()}")

    // generateSequence — null で終了します。
    val countdown = generateSequence(10) { if (it > 1) it - 1 else null }
    println("カウントダウン: ${countdown.toList()}")

    println()

    // sequence ビルダー — フィボナッチ数列
    val fibonacci = sequence {
        var a = 0
        var b = 1
        while (true) {
            yield(a)
            val next = a + b
            a = b
            b = next
        }
    }
    println("フィボナッチ(15件): ${fibonacci.take(15).toList()}")

    println()

    // asSequence — 遅延評価で効率的に処理します。
    println("=== リスト vs シーケンス ===")

    // リスト(中間リストを都度生成)
    val listResult = (1..1000000)
        .filter { it % 2 == 0 }   // 50万件のリスト生成
        .map { it * it }           // さらに50万件のリスト生成
        .first()
    println("最初の偶数の2乗: $listResult")

    // シーケンス(最初に条件を満たした時点で停止)
    val seqResult = (1..1000000).asSequence()
        .filter { it % 2 == 0 }   // 遅延(まだ実行されない)
        .map { it * it }           // 遅延(まだ実行されない)
        .first()                   // ここで実行 — 2件の処理で完了
    println("シーケンスの結果: $seqResult")
}
概要

シーケンスの最大のメリットは「遅延評価」です。リストでは各中間操作ごとに新しいコレクションを生成しますが、シーケンスは終端操作が呼ばれるまで何も実行しません。少数の要素を取り出す場合や大量データの処理ではシーケンスが効率的です。

注意: 無限シーケンスを使う場合は必ず『take()』や『first()』などで取り出す件数を制限してください。終端操作をかけると無限ループになります。

シーケンスの終端操作はシーケンス — 終端操作を、コルーチンとの組み合わせはFlow — 基本を参照してください。

記事の間違いや著作権の侵害等ございましたらお手数ですがまでご連絡頂ければ幸いです。