IEnumerable<T>をピボット集計するライブラリ書いた
IEnumerableをピボット集計するライブラリ書いた
※MVC5用
世間がコロナコロナうっせーのでムシャクシャしてやった。
よくある話
「これをピボットみたいにしてほしい。Excelみたいに。Excelみたいに。」
すげぇ面倒。
面倒ポイント
- 列数が不定なのでタイトル行と明細行でそれぞれ横方向のループで描画する必要がある
- 列や行をrowspanやcolspanで結合させるためにそのセルの下位に位置するセルを計算する必要がある。
- 行方向だと特に前の行でセルが結合済みだったりするのでどの列ヘッダから描画すべきかフラグ管理が鬱陶しい。
- 小計や合計を出そうとすると更に倍ぐらい面倒くさい。
書いた
qyen/ToPivotTable: Convert IEnumerable to pivot table on C#
model.pivot = DB.ToPivotTable(
new List<PivotColumn<MockData>>() {
// carの頭文字を逆順で集計
new PivotColumn<MockData>("initial",(t)=>t.car.Substring(0,1),(t)=>t.car.Substring(0,1)){
Order=PivotOrder.Descending,
},
new PivotColumn<MockData>("car"),
},
new List<PivotColumn<MockData>>() {
//スペース区切りのJobの最初の単語をカテゴリとして集計
new PivotColumn<MockData>("category",(t)=>t.Job.Split(' ').First(),(t)=>t.Job.Split(' ').First()),
//スペース区切りのJobの2番め以降をJobとして集計
new PivotColumn<MockData>("Job",(t)=>string.Join(" ",t.Job.Split(' ').Skip(1))),
},
new List<PivotMeasure<MockData>>() {
// 集計するのはcashの平均値
PivotMeasure<MockData>.Average("Avg.Cash",(t)=>t.cash),
}
);
しくみ
ざっくりとこう分けて
データ構成だけに着目するとColumn(0)..Column(n)をキーにしたツリー構造
と、見ることができる。
行列ヘッダ
LinqのIEnumerable<T>.GroupBy()
はIEnumerable<IGrouping<T>>
を返し、IGroupingはIEnumerableのサブクラスであるため、
foreach (var group0 in source.GroupBy(<Column0>)){
foreach (var group1 in group0.GroupBy(<Column1>)){
foreach (var group2 in group1.GroupBy(<Column2>)){
:
}
}
}
という形で深堀りできるので、再帰を使って一気にツリーを生成してる。
ToPivotTable/PivotTable.cs at master · qyen/ToPivotTable
- Enumerable.GroupBy メソッド (System.Linq) | Microsoft Docs
- IGrouping インターフェイス (System.Linq) | Microsoft Docs
構造的に行も列も同じ。
measure
measureは
- Tから値を取り出すValueGetter
- 値を集計する aggregater function
で成り立ってる。
Pivotから見れば行列の座標から抽出したリストに対して集計して値を出す部分を委譲するのがこのMeasure。
値の取り出し
この図のように、あるセルを表す集合ListOfCell
はそのセルの座標となる各ヘッダーセルの値で元集合をフィルターしたものになる。
そこにMeasureを通すと出力すべき値が取り出せる。
小計や合計の取り出し
小計や合計の値は、そのセルの座標となる各ヘッダーセルのうち合計ヘッダーセルでないものの値で元集合をフィルターしたものから算出できる。
今後とか
列定義と集計すべき値が定義としてあるんだから先にGroupBy(Column(0)..Column(n)).Select(Column(0)..Column(n),Measure(0)..Measure(m))
みたいに集計しちゃえばCPUに優しい感じになりそうなんだけど、どうやって実装したもんか。
コロナがすべてわるい。
Author And Source
この問題について(IEnumerable<T>をピボット集計するライブラリ書いた), 我々は、より多くの情報をここで見つけました https://qiita.com/qyen/items/2d5c7d75e16d7a4fc93f著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .