LoginSignup
3
4

More than 5 years have passed since last update.

IxのBufferを使ってシーケンスをグループ化する

Posted at

はじめに

Interactive Extensions(Ix)のBufferというメソッドが便利なので紹介します。

利用するにはnugetでSystem.Interactiveのインストールが必要です。

環境

  • .Net Framework 4.6.1
  • System.Interactive 3.2.0

基本的な使い方

シーケンスを決められた数ずつ分割したい場合に利用します。

1. 渡す引数が1つの場合

例1

IEnumerable<IList<int>> groups = Enumerable.Range(1, 9).Buffer(4);

・出力結果

グループ1 グループ2 グループ3
1 2 3 4 5 6 7 8 9

第一引数の値ずつにグループ化された複数のシーケンスを返します。例1では4個ずつに区切られた3つのリストが返却されます。

2. 渡す引数が2つの場合

第一引数 > 第二引数

例2

IEnumerable<IList<int>> groups = Enumerable.Range(1, 9).Buffer(5, 2);

・出力結果

グループ1 グループ2 グループ3 グループ4 グループ5
1 2 3 4 5 3 4 5 6 7 5 6 7 8 9 7 8 9 9

第二引数がある場合も第一引数の値ごとにグループ化が行われます。ただしグループ化開始位置が第二引数の値だけ逐次進みます。例2ではグループ1に1始まりの5つのデータ、グループ2に3始まりの5つのデータが入ります。

第一引数 < 第二引数

例3

IEnumerable<IList<int>> groups = Enumerable.Range(1, 9).Buffer(2, 3);

・出力結果

グループ1 グループ2 グループ3
1 2 4 5 7 8

例2と同様、第二引数の値だけグループ化開始位置が逐次進みます。例2では重複してグループ化されている要素がありましたが、例3では選択されない要素が発生します。

備考

  • 例2で、ある要素が複数のグループに割り当てられる場合も列挙は要素ごとに一回しか行われない。

  • 引数が2つある場合で両者が同じ値なら引数1つのときと処理内容は変わらない。

具体的な使用例

  • 支払明細を顧客と支払い方法ごとにグループ化して、グループごとに1ページに表示する。
  • ただし1ページに表示されるのは最大20明細とする。

という要件がきたときに1ページあたりの情報をどのように選択するか考えます。

具体例
// 支払明細
class Payment
{
    // 顧客ID
    public string CustomerID { get; set; }
    // 支払い方法
    public string PaymentMethodCode { get; set; }
    // 支払額
    public decimal Amount { get; set; }
    // 支払日
    public DateTime Date { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        // 全データ取得用のメソッドは別にあるとする
        var payments = SelectPayments();

        // 1ページごとにグループ化されたシーケンスを得られる
        var paymentPages =
            payments
            .GroupBy(x => new { x.CustomerID, x.PaymentMethodCode })
            .SelectMany(x => x.Buffer(20)) // 20:明細最大行数

        // .SelectMany(x => x.Buffer(20) は
        // .Select(x => x.Buffer(20)).SelectMany(x => x) とも書ける
    }
}

要件を読み解くと「顧客と支払い方法」をキーにしたグループ化が必要となるので、まずGroupByを行います。

つぎに最大行数20でのグループ化も必要なのでBufferを呼び出し、20行ごとでのグループ化を行います。

そうするとグループ化が2回行われたシーケンスが得られます。このままでは階層が深いため扱いやすい形にするため最後にSelectManyを行いシーケンスを1段階フラットなものにします。

このように実務で使う場合はGroupBy ToLookup SelectManyといったグループを扱う他のメソッドと組み合わせることで力を発揮します。

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4