combineとzip:複数のFlowを統合する
複数のFlowをcombineし、発行内容をzipでまとめます。
「combineとzip:複数のFlowを統合する」はCoddyKit上の無料Kotlin Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはKotlin Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Kotlin Academyコースには全4レッスンが含まれています。
フローを結合する理由
実際のアプリでは、複数のデータストリームを結合することがよくあります。たとえば、ユーザー設定とネットワークデータ、フォームフィールドとバリデーション状態などです。Kotlin Flowには、そのためのzip、combine、mergeが用意されています。
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val names = flowOf("Alice", "Bob", "Carol")
val ages = flowOf(30, 25, 35)
names.zip(ages) { name, age -> "$name is $age" }
.collect { println(it) }
}zip:対応する値の発行
zipは、値の発行を順番どおりに1対1で対応付けます。短い方のフローが終了すると停止します。
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val a = flowOf(1, 2, 3, 4) // 4 elements
val b = flowOf("a", "b", "c") // 3 elements — zip stops here
a.zip(b) { n, s -> "$n-$s" }
.collect { println(it) } // 1-a, 2-b, 3-c
}combine:最新値
combineは、フローのいずれかが値を発行するたびに、各フローの最新値を使って新しい値を発行します。両方のフローが少なくとも1回は値を発行している必要があります。
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val flow1 = MutableStateFlow(1)
val flow2 = MutableStateFlow("a")
combine(flow1, flow2) { n, s -> "$n-$s" }
.take(1)
.collect { println(it) } // 1-a
}combineとzipの違い
zipは対応するペアを待ちます。combineは最新値を使って更新のたびに処理します。リアクティブUI(たとえば2つのフォームフィールド)にはcombineを、順番に対応付ける場合にはzipを使用します。
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
// zip: 1-a, 2-b
val nums = flowOf(1, 2).zip(flowOf("a", "b")) { n, s -> "$n-$s" }
nums.collect { println("zip: $it") }
// combine fires more:
combine(flowOf(1, 2), flowOf("a")) { n, s -> "$n-$s" }
.collect { println("combine: $it") }
}merge:フローのインターリーブ
mergeは、複数のフローから値が到着した順に、対応付けを行わず発行します。出力順序は値が発行されるタイミングによって決まります。
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val a = flow { emit("A1"); delay(50); emit("A2") }
val b = flow { delay(25); emit("B1") }
merge(a, b).collect { println(it) } // A1, B1, A2
}3つ以上のフローでcombineを使用する
combineは複数のフローに対応しています。フローをvarargとして渡すと、ラムダにはすべての最新値が渡されます。
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val a = MutableStateFlow("hello")
val b = MutableStateFlow(42)
val c = MutableStateFlow(true)
combine(a, b, c) { s, n, flag -> "$s-$n-$flag" }
.take(1)
.collect { println(it) } // hello-42-true
}flatMapMerge:内部フローの並行処理
flatMapMergeは各要素をフローに変換し、すべての内部フローを並行して収集しながら、その出力を結合します。
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
(1..3).asFlow()
.flatMapMerge { n ->
flow { delay(100L - n * 10); emit("result-$n") }
}
.collect { println(it) }
}flatMapLatest:新しい値でキャンセル
flatMapLatestは、上流から新しい要素が到着すると現在の内部フローをキャンセルします。入力中の検索に最適です。
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
flowOf("k", "ko", "kot", "kotl", "kotli", "kotlin")
.flatMapLatest { query ->
flow {
delay(50) // simulate debounced search
emit("Result for: $query")
}
}
.collect { println(it) } // only "Result for: kotlin"
}トランザクションの対応付けにzipを使用する
zipを使用して2つのストリームからのイベントを対応付けます。たとえば、ユーザー操作とサーバー確認を対応付けることで、1対1の対応関係を保証できます。
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val orders = flowOf("Order1", "Order2", "Order3")
val confirmations = flowOf("Confirmed", "Confirmed", "Rejected")
orders.zip(confirmations) { order, status -> "$order: $status" }
.collect { println(it) }
}フォームバリデーションにcombineを使用する
ユーザー名とパスワードのフローをcombineして、フォームの有効性をリアクティブに計算します。どちらかのフィールドが変更されるたびに更新されます。
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val username = MutableStateFlow("")
val password = MutableStateFlow("")
val isValid = combine(username, password) { u, p ->
u.length >= 3 && p.length >= 8
}
username.value = "alice"
password.value = "secure123"
println(isValid.first()) // true
}複数ソースのローディングにonEach + combineを使用する
ローディングフラグとデータフローをcombineして、複数の独立したソースから単一のUI状態オブジェクトを生成します。
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
data class UI(val loading: Boolean, val data: String)
fun main() = runBlocking {
val loading = MutableStateFlow(true)
val data = MutableStateFlow("")
combine(loading, data) { l, d -> UI(l, d) }
.take(2)
.collect { println(it) }
data.value = "result"
loading.value = false
}クイックチェック
zipとcombineの主な違いは何ですか。
復習
zipは値の発行を順番に対応付けます。combineは最新値を使って、いずれかの更新時に処理します。mergeは独立したフローをインターリーブします。flatMapLatestは古くなった内部フローをキャンセルします。対応付けが必要か、リアクティブな更新が必要かに応じて選択します。
よくある質問
「combineとzip:複数のFlowを統合する」レッスンは無料ですか?
はい。「combineとzip:複数のFlowを統合する」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Kotlin Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Kotlin Academyコースには全4レッスンが含まれています。
「combineとzip:複数のFlowを統合する」で何を学びますか?
複数のFlowをcombineし、発行内容をzipでまとめます。 ブラウザで直接実行するハンズオンコードでKotlin Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Kotlin Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのKotlin Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。
「combineとzip:複数のFlowを統合する」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このKotlin Academyレッスンでコードを書いて実行できますか?
はい。すべてのKotlin Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- Flow演算子:map、filter、transform、take
- catchとonCompletion:Flowのエラー処理
- combineとzip:複数のFlowを統合する
- flowOnとbuffer:コンテキストとバックプレッシャー