国产精品天干天干,亚洲毛片在线,日韩gay小鲜肉啪啪18禁,女同Gay自慰喷水

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

第 110 講:C# 3 之查詢表達式(十四):group-by 的底層原理

2022-05-16 22:38 作者:SunnieShine  | 我要投稿

今天我們要講的是倒數(shù)第二個關鍵字用法 group-by 從句的用法,以及 group-by-into 的用法,它們對應的底層原理。

說了好半天了,大家都應該看得出來,實際上關鍵字全都是被翻譯成一個一個的方法調(diào)用,僅此而已。也不是特別復雜,只是建議寫關鍵字是因為好用好學。不過,group-by 這個就不是那么好用了,畢竟牽扯到分組的理論就不是那么好理解了。

Part 1 IGrouping 接口和 GroupBy 方法

非常高興我們再一次和這個接口類型見面了。這個接口類型在早期我們簡單說過,它就是半個字典類型。它不帶有完整的鍵值對查詢的過程,但它至少包含了一對多的關系,一對多的“一”是 Key 屬性,表示當前分組下的鍵;而一對多的“多”對應的就是集合里的所有元素了。我們還說過,它使用起來就是一次 foreach 循環(huán);而直接使用 Key 屬性就可以獲取分組的分組依據(jù)的數(shù)值(也就是鍵)。

是的,掌握這些就足矣了。下面我們來說說 GroupBy 方法組。

實際上,group-by(包括后面說的 group-by-into)都被直接翻譯成了 GroupBy 的方法調(diào)用。這個方法略顯復雜。先舉個例子吧,為了用這個方法。

假設我想給一個學生列表(比如包含我、炭治郎和禰豆子等等的學生)按照學生的性別分組:

我們可以看到這里的 selection 變量用到了 group-by 從句。

它等于什么呢?它等于這么寫:

實際上可以從代碼發(fā)現(xiàn),簡化挺多的。首先我們直接就把 by 后面的依據(jù)改成了 lambda 的形式,而 lambda 里的參數(shù)名稱,就是 groupby 關鍵字中間夾的這個名字。

很好理解。因為我們分組只需要給出分組依據(jù)即可;而分組依據(jù)要想在運行期間執(zhí)行和得到運用的話,直接傳入一個實際的 student.IsBoy 是不合適的,因為大家都知道,一個變量就代表的是一個值,因此這么寫實際上是直接把 IsBoy 的結果給直接傳過去了,這肯定是不合理的。在上一講的內(nèi)容里我們說過,要想暫時存儲一下操作,我們用到的思路是使用委托類型的實例來完成。因為委托就可以達到一種后期來做的工作,剛好我們這里的分組依據(jù)和排序依據(jù)是類似的,就是需要這樣的處理,才能被后續(xù)調(diào)用。

那么,這樣就算理解了,對吧。下面我們來看看稍微復雜一些的,別的 GroupBy 的重載。

Part 2 GroupBy 方法組

實際上,GroupBy 方法包含 8 個重載。這就是為啥這玩意兒復雜的原因。

  • 集合.GroupBy(分組依據(jù), 元素依據(jù), 映射依據(jù))

  • 集合.GroupBy(分組依據(jù), 元素依據(jù), 映射依據(jù), 相等比較器)

  • 集合.GroupBy(分組依據(jù), 元素依據(jù))

  • 集合.GroupBy(分組依據(jù), 元素依據(jù), 相等比較器)

  • 集合.GroupBy(分組依據(jù), 映射依據(jù))

  • 集合.GroupBy(分組依據(jù), 映射依據(jù), 相等比較器)

  • 集合.GroupBy(分組依據(jù))(上一部分用到的方法)

  • 集合.GroupBy(分組依據(jù), 相等比較器)

我們簡單說說吧。帶有相等比較器的那四個其實不必多說了,在前文的很多內(nèi)容已經(jīng)說過不少了,就是用來對于任何稍微復雜一些的數(shù)據(jù)類型進行自定義相等判斷的時候會用到的對象。

我們重點是說說剩下的四個不帶相等比較器的方法。

2-1 利用一對多改變迭代結果:GroupBy(分組依據(jù), 映射依據(jù))

先來說這個。這個方法需要傳入兩個 lambda,其中第一個 lambda 和前文描述的是一樣的,就是分組依據(jù);而第二個 lambda 是多出來的參數(shù)。這個 lambda 我們要求的是傳入兩個參數(shù),第一個參數(shù)是分組依據(jù)的那個值(你可以簡單理解成分組出來的那個鍵),而第二個參數(shù)則是該分組的所有元素。

假設我們?nèi)匀贿€是按照前文給的按學生性別分組,那么得到的序列顯然是兩個“一對多”的列表。啥?為啥是兩個?因為一個分組是針對于男生的序列,另外一個是針對于女生的序列,所以是兩個咯。為啥又是一對多呢?因為這兩個序列里,同一個序列里的所有對象的性別是相同的,比如男生的都在前面這一組,女生則都在后面這一組。那么男生和女生作為分組的依據(jù)的話,那自然就是一對多的關系咯。

那么,有些時候我們可能會將這樣的一對多的序列在方法里就完成迭代,于是我們可能會這么用方法:

請看這個例子。這個例子的 GroupBy 傳入了額外的一個參數(shù),是一個帶兩個參數(shù)的 lambda。這兩個參數(shù)就表示的是分組后的結果的這個一對多的“一”和一對多的“多”。

我們在這個 lambda 里寫了復雜的執(zhí)行過程:首先先得到 isBoy 這個布爾結果,如果是 true 就說明是男生,那么 genderString 就是 Boys: 這個字符串;而如果是 false 就說明是女生,那么 genderString 就是 Girls: 這個字符串。

然后,我們用到一個 string.Join 方法,里面的第二個參數(shù)則是獲取整個序列里所有學生的名字屬性,然后整合起來,作為字符串拼接的對象。string.Join 大家再熟悉不過了,就是拼接一個序列里的所有成員的字符串寫法,然后指定一個參數(shù)表示拼接的時候用什么字符串作為分隔。

最后,我們使用 string.Format 拼接前面給的 genderString 變量和 studentNames 變量。至此返回這個字符串結果。

這樣,我們就完成了這個方法的使用;這個方法返回的結果是什么類型的呢?剛才不是我們傳入了第二個參數(shù)嗎?第二個參數(shù)這個 lambda 不是返回一個字符串嗎?所以這個 selection 執(zhí)行后,得到的序列其實是 IEnumerable<string> 類型的。

那么,我們從第 11 行開始遍歷迭代這個 selection 變量,得到每一個字符串,直接輸出。我們看看能得到什么結果:

是的,就是我們在第二個 lambda 里返回的每一個元素的結果,被我們最后通過 foreach 循環(huán)給迭代出來了。這就是這個方法的用法。還行,對吧。

2-2 改變一對多的多:GroupBy(分組依據(jù), 元素依據(jù))

這個方法看起來復雜,但實際上比前面那個還簡單。這個方法也需要兩個參數(shù),而且第二個參數(shù)也是 lambda,不過這個參數(shù)則表示的是怎么去將一對多的多給體現(xiàn)出來。

我們前文不是搞了一個按照男女的分組嗎,現(xiàn)在我們只需要顯示學生的名字,那么我們就只需要提取出它的名字而已,而不需要完整地把 Student 類型的實例當結果給迭代出來。于是,我們可以這么做:

這個例子,我們可以看到,我們額外帶了一個 lambda。不過這個 lambda 只需要傳入一個參數(shù)即可。這個參數(shù)其實就是我們映射的元素。

在我們多給出了這個 lambda 之后,該方法的返回值也會跟著變:它會變成 IEnumerable<IGrouping<bool, string>> 類型。我們之前說過,長泛型名稱的理解辦法是從內(nèi)到外。先把最外側的這個 IEnumerable<> 拿掉,我們可以得到 IGrouping<bool, string>。這其實就是指的一個一對多關系,一對多的“一”是 bool 類型,而一對多的“多”則是 string 類型。為啥是 string 了呢?因為我們剛才第二個額外的 lambda 規(guī)定了映射的結果實際上不再是 Student 實例了,而是一個字符串。

由于我們指定了字符串當結果,因此一對多之后的多就是這個字符串了。因此我們直接可以通過迭代集合,Key 屬性就不多說了,而內(nèi)部遍歷這個一對多列表,就可以得到每一個元素都是 string 的實例了。

還是看下結果吧:

確實是合理的。那么這個方法我們也說完了。

2-3 融合到一起:GroupBy(分組依據(jù), 元素依據(jù), 映射依據(jù))

如果我們試著把前面這兩個 rua 到一起呢?是的,GroupBy 也可以做到。不過這次我們需要傳入三個 lambda 當參數(shù)了。注意,順序不要寫錯了:顯示分組依據(jù),然后是傳一個參數(shù)的 lambda,最后才是傳兩個參數(shù)的 lambda。

好理解嗎?第一個 lambda 是分組依據(jù),就不多說了;第二個參數(shù)是元素依據(jù),到底每一個元素應該是什么結果。此時我們將分組后的一對多序列的多改成字符串,讀取每個學生的名字就可以了;第三個參數(shù)則是這個最復雜的 lambda 了。這一次,因為我們第二個參數(shù)規(guī)定了一對多的多是什么樣的,因此第三個 lambda 里的第二個參數(shù)的參數(shù)名再叫 students 就略微不太合理了。因為我們一對多的多是學生名,所以這里的參數(shù)名我們改成了 studentNames。

然后,我們直接放在 string.Join 里當參數(shù),方便至極。

最后,我們照樣迭代序列,這個不用多改動。得到的結果應該是和前面的結果是一樣的。只不過這么寫就把操作分成三個 lambda 了。思路更清晰一些,雖然也更復雜一些。

Part 3 到頭來好像還是沒說 into 從句的等價代換啊……

哪有那么復雜呢……還記得嗎,GroupBy 方法的初始返回結果是啥類型的?序列,對吧。into 后跟的啥類型的變量?一對多的這個結果序列,對吧。那是不是就是在 GroupBy 后面加一個 Select 方法調(diào)用就可以了呢?

是的。

比如我有這么一個方法。那它是啥意思呢?

對吧。就是這么簡單。

那么,本來按慣例是想給大家呈現(xiàn)一下映射的關系圖的,但是太復雜了,我今天就先鴿了,改日有空更新文檔的時候來加吧。


第 110 講:C# 3 之查詢表達式(十四):group-by 的底層原理的評論 (共 條)

分享到微博請遵守國家法律
鲜城| 湛江市| 武冈市| 屏东市| 汽车| 蒙山县| 武宁县| 集安市| 香港| 丹东市| 嘉义市| 璧山县| 邵阳市| 绥德县| 郁南县| 阜宁县| 八宿县| 台州市| 思茅市| 曲松县| 上杭县| 类乌齐县| 宜良县| 出国| 三台县| 崇左市| 博兴县| 武威市| 青河县| 甘谷县| 西乌珠穆沁旗| 洪泽县| 婺源县| 宣化县| 通化县| 临海市| 姜堰市| 浙江省| 茌平县| 沁水县| 遵化市|