Skip to content

Select

1. 概要

Select は、上流から流れてくる各値に変換関数を適用し、その結果を下流へ流すオペレーターです。

LINQ の Select や他言語の map に相当します。上流の要素数、タイミング、完了通知、エラー通知はそのまま下流へ伝搬し、値だけが変換されます。

R3 の実装では、上流が Where である場合に内部的に WhereSelect へ最適化されるため、Where(...).Select(...) のチェーンはオーバーヘッドが最小になります。

2. シグネチャ

値を変換する

csharp
public static Observable<TResult> Select<T, TResult>(this Observable<T> source, Func<T, TResult> selector)

最も基本的な overload です。各値に selector を適用し、変換結果を下流へ流します。

csharp
source.Select(x => x * 2)

インデックス付きで変換する

csharp
public static Observable<TResult> Select<T, TResult>(this Observable<T> source, Func<T, int, TResult> selector)

selector の第2引数に 0 始まりのインデックスが渡されます。何番目の値かを利用した変換に使います。

csharp
source.Select((x, i) => $"{i}: {x}")

外部状態を使って変換する

csharp
public static Observable<TResult> Select<T, TResult, TState>(this Observable<T> source, TState state, Func<T, TState, TResult> selector)

クロージャによるキャプチャを避けたい場合に、外部状態を引数として明示的に渡せます。パフォーマンスが重要な場面で有用です。

csharp
var factor = 10;
source.Select(factor, (x, f) => x * f)

外部状態とインデックス付きで変換する

csharp
public static Observable<TResult> Select<T, TResult, TState>(this Observable<T> source, TState state, Func<T, int, TState, TResult> selector)

インデックスと外部状態の両方を利用できる overload です。

csharp
source.Select(offset, (x, i, o) => x + i + o)

overload の使い分け

overload使う場面
Select(Func<T, TResult>)通常の値変換
Select(Func<T, int, TResult>)インデックスを利用した変換
Select(TState, Func<T, TState, TResult>)クロージャ回避でパフォーマンス向上
Select(TState, Func<T, int, TState, TResult>)インデックスとクロージャ回避の両方が必要な場合

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

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

この例では、上流から 123 が流れ、Select(x => x * 10) によって 102030 として下流へ流れます。

4. サンプルコード

csharp
using R3;

var source = Observable.Range(1, 5);

source.Select(x => x * x)
    .Subscribe(x => Console.WriteLine(x));
// 出力: 1, 4, 9, 16, 25

インデックス付きの例:

csharp
using R3;

var source = Observable.Range(10, 3);

source.Select((x, i) => $"[{i}] = {x}")
    .Subscribe(x => Console.WriteLine(x));
// 出力: [0] = 10, [1] = 11, [2] = 12