web-dev-qa-db-ja.com

KotlinのIterableとSequenceはまったく同じに見えます。なぜ2つのタイプが必要なのですか?

これらのインターフェースは両方とも1つのメソッドのみを定義します

public operator fun iterator(): Iterator<T>

ドキュメンテーションには、Sequenceは遅延するように意図されていると書かれています。しかし、Iterableも怠zyではありません(Collectionに裏付けられていない限り)。

67
Venkata Raju

主な違いは、_Iterable<T>_および_Sequence<T>_のセマンティクスとstdlib拡張関数の実装にあります。

  • _Sequence<T>_の場合、拡張機能はJava Streamsintermediate操作と同様に、可能な場合は遅延して実行されます。たとえば、 _Sequence<T>.map { ... }_ は別の_Sequence<R>_を返し、toListまたはfoldが呼び出されます。

    次のコードを検討してください。

    _val seq = sequenceOf(1, 2)
    val seqMapped: Sequence<Int> = seq.map { print("$it "); it * it } // intermediate
    print("before sum ")
    val sum = seqMapped.sum() // terminal
    _

    以下を印刷します。

    _before sum 1 2
    _

    _Sequence<T>_は、Java Streamsと同様に、terminal操作で行われる作業を可能な限り削減したい場合の遅延使用と効率的なパイプライン化を目的としています。ただし、遅延により多少のオーバーヘッドが発生します。これは、小さなコレクションの一般的な単純な変換には望ましくなく、パフォーマンスが低下します。

    一般に、いつ必要かを判断する良い方法はないので、Kotlinでは、stdlib遅延は明示的に作成され、デフォルトですべてのIterablesで使用されないように_Sequence<T>_インターフェースに抽出されます。

  • _Iterable<T>_の場合、反対に、intermediate操作セマンティクスを持つ拡張機能は熱心に機能し、アイテムをすぐに処理して別のIterableを返します。たとえば、 _Iterable<T>.map { ... }_ は、マッピング結果を含む_List<R>_を返します。

    Iterableの同等のコード:

    _val lst = listOf(1, 2)
    val lstMapped: List<Int> = lst.map { print("$it "); it * it }
    print("before sum ")
    val sum = lstMapped.sum()
    _

    これは印刷されます:

    _1 2 before sum
    _

    上記のように、_Iterable<T>_はデフォルトでは非遅延であり、このソリューションはそれ自体をよく示しています。ほとんどの場合、良好な 参照の局所性 があり、CPUキャッシュ、予測、プリフェッチなどを利用します。これにより、コレクションの複数のコピーでも十分に機能し、小さなコレクションを使用する単純なケースでパフォーマンスが向上します。

    評価パイプラインをさらに制御する必要がある場合は、 Iterable<T>.asSequence() functionを使用した遅延シーケンスへの明示的な変換があります。

115
hotkey

ホットキーの答えを完成させる:

SequenceおよびIterableが要素全体でどのように反復するかに注意することが重要です。

シーケンスの例:

        list.asSequence()
            .filter { field ->
                Log.d("Filter", "filter")
                field.value > 0
            }.map {
                Log.d("Map", "Map")
            }.forEach {
                Log.d("Each", "Each")
            }

ログ結果:

フィルター-マップ-各;フィルター-マップ-各

反復可能な例:

             list.filter { field ->
                    Log.d("Filter", "filter")
                    field.value > 0
                }.map {
                    Log.d("Map", "Map")
                }.forEach {
                    Log.d("Each", "Each")
                }

フィルター-フィルター-マップ-マップ-各-各