Skip to content

MinMaxAsync

1. 概要

MinMaxAsync は、Observable シーケンスの最小値と最大値を 1 回のパスで同時に求め、その結果を Task として返すオペレーターです。結果は (T Min, T Max) のタプルとして返されます。MinAsyncMaxAsync を別々に呼び出すよりも効率的です。シーケンスが空の場合は InvalidOperationException をスローします。

2. シグネチャ

デフォルト比較による最小値・最大値

csharp
public static Task<(T Min, T Max)> MinMaxAsync<T>(
    this Observable<T> source,
    CancellationToken cancellationToken = default)

型パラメーター T のデフォルト比較を使用して最小値と最大値を同時に求めます。

カスタム比較子による最小値・最大値

csharp
public static Task<(T Min, T Max)> MinMaxAsync<T>(
    this Observable<T> source,
    IComparer<T> comparer,
    CancellationToken cancellationToken = default)

IComparer<T> を指定して、独自の比較ロジックで最小値・最大値を判定します。

セレクターによる射影後の最小値・最大値

csharp
public static Task<(TResult Min, TResult Max)> MinMaxAsync<T, TResult>(
    this Observable<T> source,
    Func<T, TResult> selector,
    CancellationToken cancellationToken = default)

各要素を selector で変換した結果から最小値と最大値を同時に求めます。

セレクター + カスタム比較子による最小値・最大値

csharp
public static Task<(TResult Min, TResult Max)> MinMaxAsync<T, TResult>(
    this Observable<T> source,
    Func<T, TResult> selector,
    IComparer<TResult> comparer,
    CancellationToken cancellationToken = default)

各要素を selector で変換した結果を、指定した IComparer<TResult> で比較して最小値と最大値を同時に求めます。

オーバーロードの使い分け

オーバーロード用途
MinMaxAsync(source)要素自体のデフォルト比較を使用する場合
MinMaxAsync(source, comparer)カスタム比較ロジックを使いたい場合
MinMaxAsync(source, selector)要素の特定のプロパティから最小値・最大値を求めたい場合
MinMaxAsync(source, selector, comparer)変換後の値にカスタム比較ロジックを使いたい場合

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

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

シーケンスのすべての要素を 1 回のパスで走査し、完了時に最小値と最大値のタプルを単一の結果として出力します。

4. サンプルコード

csharp
// 基本的な使い方:数値シーケンスの最小値と最大値を同時に取得
var source = new[] { 3, 7, 2, 9, 5 }.ToObservable();

var (min, max) = await source.MinMaxAsync();
Console.WriteLine($"Min: {min}, Max: {max}");
// Min: 2, Max: 9
csharp
// セレクターを使用してオブジェクトのプロパティから取得
var temperatures = new[]
{
    new { City = "東京", Temp = 28.5 },
    new { City = "札幌", Temp = 18.2 },
    new { City = "那覇", Temp = 32.1 },
    new { City = "仙台", Temp = 22.7 },
};

var (minTemp, maxTemp) = await temperatures.ToObservable()
    .MinMaxAsync(t => t.Temp);

Console.WriteLine($"最低気温: {minTemp}°C, 最高気温: {maxTemp}°C");
// 最低気温: 18.2°C, 最高気温: 32.1°C
csharp
// カスタム比較子を使用
var comparer = Comparer<string>.Create((a, b) => a.Length.CompareTo(b.Length));
var (shortest, longest) = await new[] { "apple", "hi", "watermelon" }
    .ToObservable()
    .MinMaxAsync(comparer);

Console.WriteLine($"最短: {shortest}, 最長: {longest}");
// 最短: hi, 最長: watermelon
csharp
// セレクターとカスタム比較子を併用
var words = new[] { "apple", "HI", "Watermelon" }.ToObservable();
var comparer = StringComparer.OrdinalIgnoreCase;

var (minWord, maxWord) = await words.MinMaxAsync(x => x, comparer);
Console.WriteLine($"最小: {minWord}, 最大: {maxWord}");
// 最小: apple, 最大: Watermelon