當旋律悄然劃過時空的軌跡,每一首歌就像一顆星辰,閃耀著創作者獨有的靈魂。 你是否曾想過,這些音符與樂章之間,是否也隱藏著某種秩序?某種——相似而未被察覺的連結 ?
在現實中,我們以風格定義音樂,以性別分類聲線,以名字尋找熟悉。 在程式語言的世界中,我們用 GroupBy
尋找規律,試圖透過「分組」理解資料之間微妙的關係。這不只是邏輯的操作,更像是一場哲學的提問:
什麼定義了我們的「相同」?
在群體之中,我們究竟選擇呈現什麼?又忽略了什麼?
今天,讓我們從一份歌手與歌曲的資料出發,探索 LINQ 中 GroupBy
的靈魂。
MS 文件中的命名解析 官方文件連結
交響樂需要指揮的手勢,GroupBy
也仰賴幾個核心角色來指引分組的方式與結果
keySelector
它定義了分組的依據 —— 像是將歌曲按照曲風 (搖滾、爵士、古典)、調性 (大調、小調)、或是演出者 進行分類。每一個 key 就像樂章中的主題,決定了整體的情緒。
comparer
當我們決定依照某個欄位分組後,還需要定義「何謂相同」。 是 Ado
和 ado
這兩個名字?還是說它們應被視為不同?這就像辨識旋律中的細微差異——不同演奏者的詮釋是否屬於同一首曲子?
elementSelector
分好組之後,我們要選擇的是:組內要呈現什麼? 是整筆資料、只顯示歌曲名?還是演出者的性別?這像是在決定觀眾到底看哪一段表演。
resultSelector
如果說 elementSelector
是選擇每段表演的內容,resultSelector
則是決定整場演出的總呈現 。 或許我們不只要知道有哪些歌曲,而是想知道每位歌手的代表作、總共幾人參與,或某組的平均年齡——這些都是原始資料中未直接給出的價值。
讓資料說話 我們有這樣一份資料,來自世界各地的音樂人…
1 2 3 4 5 6 7 8 9 10 11 var singers = new List<Singer>{ new Singer { Name = "Ado" , Genre = "J-Pop" , Song = "Lemon" , IsFemale = true }, new Singer { Name = "ado" , Genre = "J-Pop" , Song = "Usseewa" , IsFemale = true }, new Singer { Name = "Taylor Swift" , Genre = "Pop" , Song = "Shake It Off" , IsFemale = true }, new Singer { Name = "Ed Sheeran" , Genre = "Pop" , Song = "Shape of You" , IsFemale = false }, new Singer { Name = "Beethoven" , Genre = "Classical" , Song = "Für Elise" , IsFemale = false }, new Singer { Name = "Miles Davis" , Genre = "Jazz" , Song = "Kind of Blue" , IsFemale = false } };
elementSelector / comparer 若我們希望將相同名字的歌手歸為一組,即便大小寫不同也視為相同人,可使用 StringComparer.OrdinalIgnoreCase
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 var groupedBySingerName = singers.GroupBy( s => s.Name, StringComparer.OrdinalIgnoreCase ); foreach (var group in groupedBySingerName) { Console.WriteLine($"Group Key: {group .Key} " ); foreach (var singer in group ) { Console.WriteLine($"- {singer.Name} - {singer.Song} " ); } Console.WriteLine(); }
resultSelector 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 var groupedBySingerGender = singers.GroupBy( s => s.IsFemale, (key,group ) => new { Gender = key ? "Female" : "Male" , Count = group .Count(), Songs = group .Select(s => s.Song) } ); foreach (var group in groupedBySingerGender){ Console.WriteLine($"Gender: {group .Gender} " ); Console.WriteLine($"Singer Count: {group .Count} " ); Console.WriteLine("Songs:" ); foreach (var song in group .Songs) { Console.WriteLine($"- {song} " ); } Console.WriteLine(); }
用 GroupBy 看見背後的故事 在這個例子中,GroupBy 不只幫助我們將資料歸類,它也讓我們重新思考:如何定義差異,如何尋找共通,如何呈現意義。召喚我們看見被忽略的關聯、遺落的故事,以及那個「屬於同一組」的哲學命題。