C#の配列をグループ毎に処理する(LINQ GroupBy)

C#には LINQ というライブラリがあります。

LINQ を使えばコレクション(配列や List クラスなど)に対する処理を簡単に行う事が出来ます。

 

ここでは、LINQ を使って配列をグループ毎にまとめて処理する方法について解説します。


LINQとは

LINQ は IEnumerable<T>インターフェースへの拡張メソッドとして作られています。

つまり、配列Listクラス、Dictionaryクラス、ObservableCollectionクラスなどのIEnumerable<T>インターフェースを実装するオブジェクトであればどれでも同じように使用する事ができます。

 

LINQをつかうには using で System.Linq を参照できるようにしておきましょう。

using System.Linq;

配列をグループ化する GroupByメソッド

配列をグループ化するには GroupBy メソッドを使用します。

引数にグループ化のキーとする値を指定しますが、ラムダ式を使って記述するのが簡単で一般的な方法です。

※ラムダ式の詳細はC#のラムダ式【=>】って何?をご覧ください

以下の例ではCategoryでグループ化してそれそれのPointの平均を求めています。

            TestItem[] testArray = new TestItem[6];
            testArray[0] = new TestItem() { Class = "A", Author = "太郎", Category = "国語", Point = 50 };
            testArray[1] = new TestItem() { Class = "A", Author = "太郎", Category = "算数", Point = 70 };
            testArray[2] = new TestItem() { Class = "A", Author = "次郎", Category = "国語", Point = 90 };
            testArray[3] = new TestItem() { Class = "A", Author = "次郎", Category = "算数", Point = 10 };
            testArray[4] = new TestItem() { Class = "B", Author = "三郎", Category = "国語", Point = 60 };
            testArray[5] = new TestItem() { Class = "B", Author = "三郎", Category = "算数", Point = 60 };

            IEnumerable<IGrouping<string, TestItem>> testGroup = testArray.GroupBy(o => o.Category);
            foreach (IGrouping<string, TestItem> group in testGroup)
            {
                int total = 0;
                foreach (TestItem item in group)
                {
                    total += item.Point;
                }
                Console.WriteLine("Category=" + group.Key + " Average=" + (total / group.Count()));
            }

複数の値をキーにしてグループ化

複数の値をキーにしたい場合、ラムダ式でキーとなる値を複数返す必要があります。

この場合、匿名クラスを利用するのが良さそうです。 

            Point[] testArray = new Point[5];
            testArray[0] = new Point(4, 5);
            testArray[1] = new Point(2, 6);
            testArray[2] = new Point(1, 6);
            testArray[3] = new Point(4, 2);
            testArray[4] = new Point(6, 3);

            var testGroup = testArray.GroupBy(o => new { Class = o.Class, Category = o.Category});
            foreach (var group in testGroup)
            {
                int total = 0;
                foreach (TestItem item in group)
                {
                    total += item.Point;
                }
                Console.WriteLine("Class=" + group.Key.Class + "Category=" + group.Key.Category + " Average=" + (total / group.Count()));
            }

ラムダ式の中で「new { ・・・ }」となっている部分が匿名クラスです。

「Class」と「Category」というメンバ変数を持った名前の無いクラスを作成して、それをラムダ式の戻り値としています。

 

関連記事