Linq 思考重點筆記圖解
前言
Linq 是一個很簡潔的語言,但是對於初學者,無法用視覺化的方式來思考Linq的語法,Linq的簡潔反而變成痛苦
除了經驗的累積可以降低這個痛苦之外,你可以下載LINQPad這套軟體來協助你在初學時,用視覺化的方式來學習並測試你的Linq語法是否符合預期
當你使用Group語法時,在LINQPad可以看到樹狀結構的Table,這對於我們學習Linq是很有幫助的, 如下圖所示:
對我而言,好一陣子沒有寫Linq了,這個痛苦感又回來了,要學習Linq,你可以上網找,也可以買書來學語法,但是在實務面上來說,就是沒有人提及…
「我們該如何來思考分析,幫助我們更快的寫出Linq程式」
為了一勞永逸的幫助我克服掉這種痛苦感,我寫下了這個筆記,希望讀者也能從中獲利。
不說廢話,我先講我的需求。
範例
我有一個資料來源如下,我們有一個工具列,只要使用者點擊一次工具列上的某個App的按鈕,資料庫就會多一筆如下的記錄
List<AppTrackRecordItem> (7 items) |
|||||
Name(使用者名稱) |
IsUserLogin(是否登入) |
AppId(App編號) |
MachineId(電腦名稱) |
RecordDate(記錄日期) |
Type(點擊) |
Rolen |
True |
1 |
A |
2010/4/11 下午 12:00:00 |
ClickApp |
Rolen |
True |
1 |
A |
2010/4/11 下午 01:00:00 |
ClickApp |
Stevn |
True |
2 |
A |
2010/4/11 下午 01:00:00 |
ClickApp |
Stevn |
False |
3 |
C |
2010/4/11 下午 02:00:00 |
ClickApp |
Rayxu |
False |
1 |
B |
2010/4/11 下午 02:00:00 |
ClickApp |
Yeaze |
False |
1 |
A |
2010/4/12 上午 12:00:00 |
ClickApp |
Rolen |
False |
2 |
B |
2010/4/12 上午 12:00:00 |
ClickApp |
我想匯出統計報表,告訴我每一天,有多少使用者點擊了任何一個App
第0步
第0步要先思考怎樣把資料源整理成容易計算的樹狀結構?樹狀結構的根節點是要什麼欄位?這方便我之後的匯總計算
我想要的樹狀結構如下圖,當然一開始,你沒辦法用電腦畫出這麼正式的表格,只要手繪就好。
從下圖可以知道我決定的節點是:
日期(RecordDate)
+ 電腦名稱(MachineId)
+ App編號(AppId)
IEnumerable<> (2 items) |
|||||||||||||||||||||||||||||
Date |
data |
||||||||||||||||||||||||||||
2010/4/11 上午 12:00:00 |
|
||||||||||||||||||||||||||||
2010/4/12 上午 12:00:00 |
|
第1步
接下來我手繪出我要的結果,並把正確答案寫下去
IEnumerable<> (2 items) |
|
Date |
TotalClickCount |
2010/4/11 |
5 |
2010/4/12 |
2 |
第二步
開始寫Linq程式,將第0步的表格產生出來,我使用Group語法
//來源的資料表如下
List listRec = new List();
listRec.Add(new AppTrackRecordItem() { Name = "Rolen", AppId=1, IsUserLogin = true, MachineId = "A", RecordDate = new DateTime(2010, 4, 11, 12, 00, 00), Type = AppTrackRecordItem.ActionType.ClickApp });
//省略…
//開始產生樹狀的資料結構
var result = from eachRec in listRec
group eachRec by eachRec.RecordDate.Date into groupByDate //第一層,以Date(日期)為鍵值做Group
select new
{
Date = groupByDate.Key,
data =
from eachGroupByDate in groupByDate
group eachGroupByDate by eachGroupByDate.MachineId into groupByMachine //第二層,以MachineId 為鍵值做Group
select new
{
MachineId = groupByMachine.Key,
data =
from a in groupByMachine
group a by a.AppId into groupByAppId //第三層,以AppId 為鍵值做Group
select new
{
AppId = groupByAppId.Key,
ClickCount = groupByAppId.Count()
}
}
};
以上的Linq語法,就會產生出如第0步所要的樹狀結構出來,你可以把上述程式碼貼到LinqPad軟體執行,就可以看到樹狀的表格了
有了樹狀結構了,再參考第1步我要的結果,就可以從肉眼看出我要的資料要從哪裏加總
第0步表裏面紅色的字就是我要加總的值,並且我要保留第一層表的Date欄位,做為最終的輸出結果
最後完成的Linq如下:
最後的輸出就是我們要的表單了~
第三步
var res = from r in result //第一個from,在第一層Table
select new //select new 想成定義新的tabel,裏面就是欄位內容的定義
{
Date = r.Date,
TotalClickCount= (from rr in r.data // 兩次from 指到第三層的Table,並用Sum方法來加總第三層 Table裏面的ClickCount欄位的值
from rrr in rr.data
select rrr).Sum(s => s.ClickCount)
};