Skip to content

ToLookupAsync

1. 概要

ToLookupAsync は、Observable シーケンスのすべての要素を収集し、ILookup<TKey, T> または ILookup<TKey, TElement>Task として返すオペレーターです。ToDictionaryAsync と異なり、同じキーに対して複数の値をグルーピングできます。シーケンスが完了するまで要素をバッファリングします。

2. シグネチャ

キーセレクターのみ

csharp
public static Task<ILookup<TKey, T>> ToLookupAsync<T, TKey>(
    this Observable<T> source,
    Func<T, TKey> keySelector,
    CancellationToken cancellationToken = default)

各要素からキーを抽出し、同じキーを持つ要素をグループ化します。

キーセレクターと要素セレクター

csharp
public static Task<ILookup<TKey, TElement>> ToLookupAsync<T, TKey, TElement>(
    this Observable<T> source,
    Func<T, TKey> keySelector,
    Func<T, TElement> elementSelector,
    CancellationToken cancellationToken = default)

各要素からキーと値の両方を変換してルックアップに格納します。

キーセレクターとカスタム等値比較子

csharp
public static Task<ILookup<TKey, T>> ToLookupAsync<T, TKey>(
    this Observable<T> source,
    Func<T, TKey> keySelector,
    IEqualityComparer<TKey> comparer,
    CancellationToken cancellationToken = default)

キーの比較にカスタムの IEqualityComparer<TKey> を使用します。

キーセレクター、要素セレクター、カスタム等値比較子

csharp
public static Task<ILookup<TKey, TElement>> ToLookupAsync<T, TKey, TElement>(
    this Observable<T> source,
    Func<T, TKey> keySelector,
    Func<T, TElement> elementSelector,
    IEqualityComparer<TKey> comparer,
    CancellationToken cancellationToken = default)

キーと値の変換、およびカスタムのキー比較ロジックをすべて指定します。

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

オーバーロード用途
ToLookupAsync(source, keySelector)要素自体を値として格納する場合
ToLookupAsync(source, keySelector, elementSelector)値も変換したい場合
ToLookupAsync(source, keySelector, comparer)カスタムキー比較が必要な場合
ToLookupAsync(source, keySelector, elementSelector, comparer)値の変換とカスタムキー比較の両方が必要な場合

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

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

シーケンスのすべての要素をキーごとにグループ化して収集し、完了時にルックアップを単一の結果として出力します。

4. サンプルコード

csharp
// 基本的な使い方:カテゴリごとにグループ化
var products = new[]
{
    new { Category = "果物", Name = "りんご" },
    new { Category = "野菜", Name = "にんじん" },
    new { Category = "果物", Name = "バナナ" },
    new { Category = "野菜", Name = "キャベツ" },
    new { Category = "果物", Name = "みかん" },
};

var lookup = await products.ToObservable()
    .ToLookupAsync(p => p.Category);

foreach (var item in lookup["果物"])
{
    Console.WriteLine(item.Name);
}
// りんご
// バナナ
// みかん
csharp
// 要素セレクターを使用して名前だけを格納
var products = new[]
{
    new { Category = "果物", Name = "りんご" },
    new { Category = "野菜", Name = "にんじん" },
    new { Category = "果物", Name = "バナナ" },
};

ILookup<string, string> lookup = await products.ToObservable()
    .ToLookupAsync(p => p.Category, p => p.Name);

Console.WriteLine(string.Join(", ", lookup["果物"]));
// りんご, バナナ
csharp
// 存在しないキーへのアクセスは空のシーケンスを返す(例外なし)
var numbers = new[] { 1, 2, 3, 4, 5 }.ToObservable();

ILookup<string, int> lookup = await numbers
    .ToLookupAsync(n => n % 2 == 0 ? "偶数" : "奇数");

Console.WriteLine(lookup["偶数"].Count()); // 2
Console.WriteLine(lookup["存在しないキー"].Count()); // 0