C#, LINQのGroupByで重複した要素と重複した要素が何個あるかを得る
はじめに
集計対象が複数のプロパティを持つオブジェクトの重複した要素と重複した要素が何個あるかが欲しくなった1。
集計対象が1オブジェクト2の配列やコレクションだったらDistinct
からのCount
で済む。
ソースコード全文
using System; using System.Linq; namespace Sample { class Program { static void Main(string[] args) { // 集計対象 var Points = new[] { new { X = 0, Y = 0 }, new { X = 0, Y = 1 }, new { X = 0, Y = 1 }, new { X = 1, Y = 0 }, new { X = 1, Y = 0 }, new { X = 1, Y = 0 }, new { X = 1, Y = 1 }, new { X = 1, Y = 1 }, new { X = 1, Y = 1 }, new { X = 1, Y = 1 }, }; // Method syntax // 1プロパティをグループ化 var pointXs = Points.GroupBy(point => point.X); /* ↓表示結果 0 1 */ foreach(var pointX in pointXs) { Console.WriteLine(pointX.Key); } // 2プロパティをグループ化、おまけで重複したグループ数を得る var points = Points.GroupBy(point => new { point.X, point.Y }) .Select(point => new { point.Key.X, point.Key.Y, Count = point.Count() }); /* ↓表示結果 { X = 0, Y = 0, Count = 1 } { X = 0, Y = 1, Count = 2 } { X = 1, Y = 0, Count = 3 } { X = 1, Y = 1, Count = 4 } */ foreach(var point in points) { Console.WriteLine(point); } #if false // Query syntax var result = from pointXs in Points group pointXs by pointXs.X; foreach(var item in result) { Console.WriteLine(item.Key); } var points = from pointXYs in Points group pointXYs by new { pointXYs.X, pointXYs.Y } into point select new { point.Key.X, point.Key.Y, Count = point.Count() }; foreach(var point in points) { Console.WriteLine(point); } #endif } } }
所感
個人的にはメソッド構文の方がクエリー構文より使いやすい。
メソッド構文はクエリー構文より命名するオブジェクトの数が少なくて済むから。
※クエリー構文はSQLっぽく書けるから好きではあるが。
※何気にクエリー構文は行頭が揃うのが良い。上記のソースコードだとfrom
とgroup
とselect
の開始位置。
補足
IDE
- Microsoft Visual Studio Community 2019
- Version 16.5.3
- Microsoft .NET Framework
- Version 4.8.03752
プロジェクト
- コンソール アプリ(C#)
- .NET Core 3.1
書いた経緯など
SQLならパッと思いつくんだけどLINQは慣れていないので書き方が分からなかった。
また、調べるのも面倒なので備忘録として書き残した。
ついでにクエリー構文も調べて書いたけど、今後はメソッド構文だけを書くか。
載せるソースコードが長くなってしまう。