Linq 思考重點筆記圖解

  • 4790
  • 0

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

IEnumerable<> (3 items)

MachineId

data

A

IEnumerable<> (2 items)

AppId

ClickCount

1

2

2

1

Sum

3

C

IEnumerable<> (1 item)

AppId

ClickCount

3

1

B

IEnumerable<> (1 item)

AppId

ClickCount

1

1

2010/4/12 上午 12:00:00

IEnumerable<> (2 items)

MachineId

data

A

IEnumerable<> (1 item)

AppId

ClickCount

1

1

B

IEnumerable<> (1 item)

AppId

ClickCount

2

1

 

第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)
             };

 

最後的輸出就是我們要的表單了~