Skip to content

CombineLatest

1. 概要

CombineLatest は、複数の Observable ソースのいずれかが新しい値を発行するたびに、各ソースの最新値を結合関数に渡して結果を生成するオペレーターです。

すべてのソースが少なくとも 1 回は値を発行した後に初めて結果が生成され、以降はいずれか 1 つのソースが新しい値を発行するたびに、他のソースの最新値と組み合わせて結果を発行します。

2. シグネチャ

2 つのソースを結合する(型付きオーバーロード)

csharp
public static Observable<TResult> CombineLatest<T1, T2, TResult>(
    this Observable<T1> source1,
    Observable<T2> source2,
    Func<T1, T2, TResult> resultSelector)

最も基本的なオーバーロードです。2 つの異なる型の Observable を resultSelector で組み合わせます。

csharp
source1.CombineLatest(source2, (x, y) => x + y)

3〜15 個のソースを結合する(型付きオーバーロード)

csharp
public static Observable<TResult> CombineLatest<T1, T2, T3, TResult>(
    this Observable<T1> source1,
    Observable<T2> source2,
    Observable<T3> source3,
    Func<T1, T2, T3, TResult> resultSelector)

3 個から最大 15 個までのソースを型安全に結合できます。各ソースは異なる型を持つことができ、resultSelector ですべてのソースの値を受け取ります。

csharp
source1.CombineLatest(source2, source3, (x, y, z) => $"{x}-{y}-{z}")

同一型の可変個数ソースを結合する(配列 / IEnumerable)

csharp
public static Observable<T[]> CombineLatest<T>(params Observable<T>[] sources)
public static Observable<T[]> CombineLatest<T>(IEnumerable<Observable<T>> sources)

同じ型の Observable を任意の個数まとめて結合します。結果は各ソースの最新値を格納した配列 T[] として発行されます。ファクトリメソッド版 CombineLatest として Observable.CombineLatest(...) の形で呼び出します。

csharp
Observable.CombineLatest(sourceA, sourceB, sourceC)

overload の使い分け

overload使う場面
2〜15 引数の型付きソース数が固定で、異なる型を組み合わせたい場合
params Observable<T>[]同一型のソースを動的な個数で結合したい場合
IEnumerable<Observable<T>>ソースのコレクションを渡したい場合

3. マーブルダイアグラム

CombineLatest のマーブルダイアグラム

すべてのソースが少なくとも 1 つの値を発行した時点から、いずれかのソースが新しい値を発行するたびに、各ソースの最新値を組み合わせた結果が下流へ流れます。

4. サンプルコード

csharp
using R3;

// 2 つのソースの最新値を結合
var subject1 = new Subject<int>();
var subject2 = new Subject<string>();

subject1.CombineLatest(subject2, (num, str) => $"{num}-{str}")
    .Subscribe(x => Console.WriteLine(x));

subject1.OnNext(1);       // まだ出力なし(subject2 が未発行)
subject2.OnNext("A");     // 出力: 1-A
subject1.OnNext(2);       // 出力: 2-A
subject2.OnNext("B");     // 出力: 2-B
subject1.OnNext(3);       // 出力: 3-B

配列オーバーロードの例:

csharp
using R3;

var sources = new[]
{
    new Subject<int>(),
    new Subject<int>(),
    new Subject<int>()
};

Observable.CombineLatest(sources.Select(s => (Observable<int>)s).ToArray())
    .Subscribe(values => Console.WriteLine(string.Join(", ", values)));

sources[0].OnNext(1);
sources[1].OnNext(2);
sources[2].OnNext(3);     // 出力: 1, 2, 3
sources[0].OnNext(10);    // 出力: 10, 2, 3

5. 補足

Zip との違い

Zip は各ソースの要素をインデックス順で 1 対 1 にペアリングするため、片方のソースが先行して発行しても、もう片方が追いつくまで結果は発行されません。一方、CombineLatest はいずれかのソースが発行するたびに最新値を再利用して結果を生成します。

ZipLatest との違い

ZipLatest は、すべてのソースが前回の発行以降に新しい値を発行したときにのみ結果を生成します。CombineLatest はいずれか 1 つのソースが発行するだけで結果を生成する点が異なります。

WithLatestFrom との違い

WithLatestFrom は、メインソースが発行したときにのみ結果を生成し、サブソースの発行では結果を生成しません。CombineLatest はどちらのソースの発行でも結果を生成します。

ファクトリメソッド版との違い

ファクトリメソッド版 CombineLatest は、同じ型の複数ソースを params または IEnumerable で受け取り、結果を T[] として発行します。異なる型のソースを型安全に結合し、結果を任意の型へ変換したい場合は、このオペレーター版を使います。