早く流れる川で

雑に書き留めた何か

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っぽく書けるから好きではあるが。
※何気にクエリー構文は行頭が揃うのが良い。上記のソースコードだとfromgroupselectの開始位置。

補足

IDE

プロジェクト

  • コンソール アプリ(C#)
    • .NET Core 3.1

書いた経緯など

SQLならパッと思いつくんだけどLINQは慣れていないので書き方が分からなかった。
また、調べるのも面倒なので備忘録として書き残した。
ついでにクエリー構文も調べて書いたけど、今後はメソッド構文だけを書くか。
載せるソースコードが長くなってしまう。


  1. 結局、使わなくてもよくなった・・・チーン

  2. intやstringなどオブジェクトのこと