【C#入門】LINQのGroupByでグループ化する(OrderByも解説)

LINQのGroupByメソッドって使ってますか?コレクションの要素をグループに分類する場合に簡潔に記述することができて便利です。この記事では、LINQのGroupByメソッドについて

  • GroupByメソッドとは
  • GroupByメソッドの使い方
  • OrderByメソッドとは
  • OrderByメソッドとはの使い方
  • 複数のキーを指定する方法

など基本的な内容から、応用的な使い方の内容についても解説していきます。今回はLINQのGroupByメソッドについて、使い方をわかりやすく解説します!

目次

GroupByメソッドとは

LINQのGroupByメソッドは、コレクションの要素をグループに分類する場合に使用します。ちなみにLINQとはコレクション(配列やList、Dictionaryなど)の要素を処理するメソッドを集めたライブラリです。

LINQのGroupByメソッドを使うと、コレクションの要素をグループに分類する処理を簡潔に記述することができます。

GroupByの使い方

GroupByメソッドはコレクションのオブジェクトから呼び出して使うことができます。GroupByメソッドの引数にはラムダ式でグループ分けのKeyを指定します。ラムダ式とは、一言で言うとメソッドを変数と同様に扱う記述様式になります。

ラムダ式の基本構文は以下のようになります。

左辺 => 右辺

左辺には、メソッドの変数を指定します。パラメータは「( )」で囲む必要がありますが、変数が1つのみの場合は「( )」を省略することができます。変数が複数の場合は、各変数を「,」(カンマ)で区切ります。

() => 右辺    // 変数なしの場合
param => 右辺    // 変数が1つの場合
(param1, param2) => 右辺    // 変数が2つの場合

変数の型はコンパイラによって自動的に推論されます。必要であれば型を指定することもできます。

(int param) => 右辺    // 変数をint型で指定

それではGroupByソッドの使い方について、サンプルコードで確認しましょう。GroupByメソッドを使うため、usingディレクティブを使ってSystem.Linqを参照しています。

using System;
using System.Collections.Generic;
using System.Linq;

namespace Sample
{
  class Test {
    public string Subj { get; set; }
    public int Points { get; set; }
    public string Name { get; set; }
    public string ClassName { get; set; }
  }
  
  class Sample
  {
    static void Main()
    {
      var result = new List<Test>() {
        new Test {Subj = "国語", Points = 90, Name = "田中 一郎", ClassName = "A"},
        new Test {Subj = "数学", Points = 80, Name = "田中 一郎", ClassName = "A"},
        new Test {Subj = "英語", Points = 70, Name = "田中 一郎", ClassName = "A"},
        new Test {Subj = "国語", Points = 60, Name = "鈴木 二郎", ClassName = "A"},
        new Test {Subj = "数学", Points = 50, Name = "鈴木 二郎", ClassName = "A"},
        new Test {Subj = "英語", Points = 80, Name = "鈴木 二郎", ClassName = "A"},
        new Test {Subj = "国語", Points = 70, Name = "佐藤 三郎", ClassName = "B"},
        new Test {Subj = "数学", Points = 80, Name = "佐藤 三郎", ClassName = "B"},
        new Test {Subj = "英語", Points = 90, Name = "佐藤 三郎", ClassName = "B"},
      };
      
      var query = result.GroupBy(x => x.Subj);
      
      foreach(var group in query) {
        Console.WriteLine(group.Key);
        foreach(var item in group) {
          Console.WriteLine("{0}:{1}点", item.Name, item.Points);
        }
      }
      
      Console.ReadKey();
    }
  }
}

実行結果:

国語
田中 一郎:90点
鈴木 二郎:60点
佐藤 三郎:70点
数学
田中 一郎:80点
鈴木 二郎:50点
佐藤 三郎:80点
英語
田中 一郎:70点
鈴木 二郎:80点
佐藤 三郎:90点

このサンプルコードでは、GroupByメソッドを使ってTestクラスのメンバ―変数Subjの値でグループ分けをしています。

複数のキーを指定する

グループ分けのキーを複数個指定することもできます。GroupByメソッドの引数でnew句を使って複数指定します。サンプルコードで確認しましょう。

using System;
using System.Collections.Generic;
using System.Linq;

namespace Sample
{
  class Test {
    public string Subj { get; set; }
    public int Points { get; set; }
    public string Name { get; set; }
    public string ClassName { get; set; }
  }
  
  class Sample
  {
    static void Main()
    {
      var result = new List<Test>() {
        new Test {Subj = "国語", Points = 90, Name = "田中 一郎", ClassName = "A"},
        new Test {Subj = "数学", Points = 80, Name = "田中 一郎", ClassName = "A"},
        new Test {Subj = "英語", Points = 70, Name = "田中 一郎", ClassName = "A"},
        new Test {Subj = "国語", Points = 60, Name = "鈴木 二郎", ClassName = "A"},
        new Test {Subj = "数学", Points = 50, Name = "鈴木 二郎", ClassName = "A"},
        new Test {Subj = "英語", Points = 80, Name = "鈴木 二郎", ClassName = "A"},
        new Test {Subj = "国語", Points = 70, Name = "佐藤 三郎", ClassName = "B"},
        new Test {Subj = "数学", Points = 80, Name = "佐藤 三郎", ClassName = "B"},
        new Test {Subj = "英語", Points = 90, Name = "佐藤 三郎", ClassName = "B"},
      };
      
      var query = result.GroupBy(x => new {Subj = x.Subj, ClassName = x.ClassName});
      
      foreach(var group in query) {
        Console.WriteLine(group.Key);
        foreach(var item in group) {
          Console.WriteLine("{0}:{1}点", item.Name, item.Points);
        }
      }
      
      Console.ReadKey();
    }
  }
}

実行結果:

{ Subj = 国語, ClassName = A }
田中 一郎:90点
鈴木 二郎:60点
{ Subj = 数学, ClassName = A }
田中 一郎:80点
鈴木 二郎:50点
{ Subj = 英語, ClassName = A }
田中 一郎:70点
鈴木 二郎:80点
{ Subj = 国語, ClassName = B }
佐藤 三郎:70点
{ Subj = 数学, ClassName = B }
佐藤 三郎:80点
{ Subj = 英語, ClassName = B }
佐藤 三郎:90点

このサンプルコードでは、GroupByメソッドの引数にnew句を使って複数のキーを設定しています。

Whereで条件を指定する

GroupByメソッドでグループに分ける際に、Whereオペレータを使って条件を絞ることもできます。

using System;
using System.Collections.Generic;
using System.Linq;

namespace Sample
{
  class Test {
    public string Subj { get; set; }
    public int Points { get; set; }
    public string Name { get; set; }
    public string ClassName { get; set; }
  }
  
  class Sample
  {
    static void Main()
    {
      var result = new List<Test>() {
        new Test {Subj = "国語", Points = 90, Name = "田中 一郎", ClassName = "A"},
        new Test {Subj = "数学", Points = 80, Name = "田中 一郎", ClassName = "A"},
        new Test {Subj = "英語", Points = 70, Name = "田中 一郎", ClassName = "A"},
        new Test {Subj = "国語", Points = 60, Name = "鈴木 二郎", ClassName = "A"},
        new Test {Subj = "数学", Points = 50, Name = "鈴木 二郎", ClassName = "A"},
        new Test {Subj = "英語", Points = 80, Name = "鈴木 二郎", ClassName = "A"},
        new Test {Subj = "国語", Points = 70, Name = "佐藤 三郎", ClassName = "B"},
        new Test {Subj = "数学", Points = 80, Name = "佐藤 三郎", ClassName = "B"},
        new Test {Subj = "英語", Points = 90, Name = "佐藤 三郎", ClassName = "B"},
      };
      
      var query = result
        .Where(x => x.Points < 70)
        .GroupBy(x => x.Subj);
      
      foreach(var group in query) {
        Console.WriteLine(group.Key);
        foreach(var item in group) {
          Console.WriteLine("{0}:{1}点", item.Name, item.Points);
        }
      }
      
      Console.ReadKey();
    }
  }
}

実行結果:

国語
鈴木 二郎:60点
数学
鈴木 二郎:50点

このサンプルコードでは、Whereオペレータを使ってTestクラスのメンバ変数Pointsの値が70未満の要素のみグループ分けしています。

Sumで合計値を求める

集計演算子を使ってグループ分けした結果の値を集計演算することができます。ここでは集計演算子Sumを使ってグループ分けした結果の合計値を求める方法をご紹介します。

using System;
using System.Collections.Generic;
using System.Linq;

namespace Sample
{
  class Test {
    public string Subj { get; set; }
    public int Points { get; set; }
    public string Name { get; set; }
    public string ClassName { get; set; }
  }
  
  class Sample
  {
    static void Main()
    {
      var result = new List<Test>() {
        new Test {Subj = "国語", Points = 90, Name = "田中 一郎", ClassName = "A"},
        new Test {Subj = "数学", Points = 80, Name = "田中 一郎", ClassName = "A"},
        new Test {Subj = "英語", Points = 70, Name = "田中 一郎", ClassName = "A"},
        new Test {Subj = "国語", Points = 60, Name = "鈴木 二郎", ClassName = "A"},
        new Test {Subj = "数学", Points = 50, Name = "鈴木 二郎", ClassName = "A"},
        new Test {Subj = "英語", Points = 80, Name = "鈴木 二郎", ClassName = "A"},
        new Test {Subj = "国語", Points = 70, Name = "佐藤 三郎", ClassName = "B"},
        new Test {Subj = "数学", Points = 80, Name = "佐藤 三郎", ClassName = "B"},
        new Test {Subj = "英語", Points = 90, Name = "佐藤 三郎", ClassName = "B"},
      };
      
      var query = result
        .GroupBy(x => x.Name)
        .Select(x => new {Name = x.Key, Sum = x.Sum(y => y.Points)});
      
      foreach(var group in query) {
        Console.WriteLine("{0}の合計点数:{1}点", group.Name, group.Sum);
      }
      
      Console.ReadKey();
    }
  }
}

実行結果:

田中 一郎の合計点数:240点
鈴木 二郎の合計点数:190点
佐藤 三郎の合計点数:240点

このサンプルコードでは、GroupByメソッドを使ってTestクラスのメンバ変数Nameの値でグループ分けを行っています。さらにグループ分けした結果に対して、集計演算子Sumを使ってTestクラスのメンバ変数Pointsの値の合計値を算出しています。

Countで数を数える

ここでは集計演算子Countを使ってグループ分けした結果の要素数を求める方法をご紹介します。

using System;
using System.Collections.Generic;
using System.Linq;

namespace Sample
{
  class Test {
    public string Subj { get; set; }
    public int Points { get; set; }
    public string Name { get; set; }
    public string ClassName { get; set; }
  }
  
  class Sample
  {
    static void Main()
    {
      var result = new List<Test>() {
        new Test {Subj = "国語", Points = 90, Name = "田中 一郎", ClassName = "A"},
        new Test {Subj = "数学", Points = 80, Name = "田中 一郎", ClassName = "A"},
        new Test {Subj = "英語", Points = 70, Name = "田中 一郎", ClassName = "A"},
        new Test {Subj = "国語", Points = 60, Name = "鈴木 二郎", ClassName = "A"},
        new Test {Subj = "数学", Points = 50, Name = "鈴木 二郎", ClassName = "A"},
        new Test {Subj = "英語", Points = 80, Name = "鈴木 二郎", ClassName = "A"},
        new Test {Subj = "国語", Points = 70, Name = "佐藤 三郎", ClassName = "B"},
        new Test {Subj = "数学", Points = 80, Name = "佐藤 三郎", ClassName = "B"},
        new Test {Subj = "英語", Points = 90, Name = "佐藤 三郎", ClassName = "B"},
      };
      
      var query = result
        .Where(x => x.Points <= 70)
        .GroupBy(x => x.Subj)
        .Select(x => new {Subj = x.Key, Count = x.Count()});
      
      foreach(var group in query) {
        Console.WriteLine("{0}で70点以下:{1}人", group.Subj, group.Count);
      }
      
      Console.ReadKey();
    }
  }
}

実行結果:

英語で70点以下:1人
国語で70点以下:2人
数学で70点以下:1人

このサンプルコードでは、GroupByメソッドを使ってTestクラスのメンバ変数Subjの値でグループ分けを行っています。Whereオペレータを使ってTestクラスのメンバ変数Pointsの値が70以下の要素に条件を絞っています。

さらに集計演算子Countを使ってグループ分け後の要素数を算出しています。

OrderByメソッドとは

LINQのOrderByメソッドは、コレクションの要素を並び替える場合に使用します。

OrderByの使い方

OrderByメソッドはコレクションのオブジェクトから呼び出して使うことができます。OrderByメソッドの引数にはラムダ式で並び替えのKeyを指定します。

昇順に並び替える場合はOrderByメソッドを使用し、降順に並び替える場合はOrderByDescendingメソッドを使用します。

using System;
using System.Collections.Generic;
using System.Linq;

namespace Sample
{
  class Test {
    public string Subj { get; set; }
    public int Points { get; set; }
    public string Name { get; set; }
    public string ClassName { get; set; }
  }
  
  class Sample
  {
    static void Main()
    {
      var result = new List<Test>() {
        new Test {Subj = "国語", Points = 90, Name = "田中 一郎", ClassName = "A"},
        new Test {Subj = "数学", Points = 80, Name = "田中 一郎", ClassName = "A"},
        new Test {Subj = "英語", Points = 70, Name = "田中 一郎", ClassName = "A"},
        new Test {Subj = "国語", Points = 60, Name = "鈴木 二郎", ClassName = "A"},
        new Test {Subj = "数学", Points = 50, Name = "鈴木 二郎", ClassName = "A"},
        new Test {Subj = "英語", Points = 80, Name = "鈴木 二郎", ClassName = "A"},
        new Test {Subj = "国語", Points = 70, Name = "佐藤 三郎", ClassName = "B"},
        new Test {Subj = "数学", Points = 80, Name = "佐藤 三郎", ClassName = "B"},
        new Test {Subj = "英語", Points = 90, Name = "佐藤 三郎", ClassName = "B"},
      };
      
      var query = result
        .OrderByDescending(x => x.Points)
        .GroupBy(x => x.Subj);
      
      foreach(var group in query) {
        Console.WriteLine(group.Key);
        foreach(var item in group) {
          Console.WriteLine("{0}:{1}点", item.Name, item.Points);
        }
      }
      
      Console.ReadKey();
    }
  }
}

実行結果:

国語
田中 一郎:90点
佐藤 三郎:70点
鈴木 二郎:60点
英語
佐藤 三郎:90点
鈴木 二郎:80点
田中 一郎:70点
数学
田中 一郎:80点
佐藤 三郎:80点
鈴木 二郎:50点

このサンプルコードでは、OrderByDescendingメソッドを使ってTestクラスのメンバ変数Pointsの値で降順に並び替えています。

複数のキーを指定する

複数のキーを指定して並び替えることもできます。第2キー以降で昇順に並び替える場合はThenByメソッドを、降順に並び替える場合はThenByDescendingメソッドを使います。

using System;
using System.Collections.Generic;
using System.Linq;

namespace Sample
{
  class Test {
    public string Subj { get; set; }
    public int Points { get; set; }
    public string Name { get; set; }
    public string ClassName { get; set; }
  }
  
  class Sample
  {
    static void Main()
    {
      var result = new List<Test>() {
        new Test {Subj = "国語", Points = 90, Name = "田中 一郎", ClassName = "A"},
        new Test {Subj = "数学", Points = 80, Name = "田中 一郎", ClassName = "A"},
        new Test {Subj = "英語", Points = 70, Name = "田中 一郎", ClassName = "A"},
        new Test {Subj = "国語", Points = 60, Name = "鈴木 二郎", ClassName = "A"},
        new Test {Subj = "数学", Points = 50, Name = "鈴木 二郎", ClassName = "A"},
        new Test {Subj = "英語", Points = 80, Name = "鈴木 二郎", ClassName = "A"},
        new Test {Subj = "国語", Points = 70, Name = "佐藤 三郎", ClassName = "B"},
        new Test {Subj = "数学", Points = 80, Name = "佐藤 三郎", ClassName = "B"},
        new Test {Subj = "英語", Points = 90, Name = "佐藤 三郎", ClassName = "B"},
      };
      
      var query = result
        .OrderByDescending(x => x.Points)
        .ThenBy(x => x.Name)
        .GroupBy(x => x.Subj);
      
      foreach(var group in query) {
        Console.WriteLine(group.Key);
        foreach(var item in group) {
          Console.WriteLine("{0}:{1}点", item.Name, item.Points);
        }
      }
      
      Console.ReadKey();
    }
  }
}

実行結果:

英語
佐藤 三郎:90点
鈴木 二郎:80点
田中 一郎:70点
国語
田中 一郎:90点
佐藤 三郎:70点
鈴木 二郎:60点
数学
佐藤 三郎:80点
田中 一郎:80点
鈴木 二郎:50点

このサンプルコードでは、OrderByDescendingメソッドを使ってTestクラスのメンバ変数Pointsの値で降順に並び替えています。さらにThenByメソッドを使ってTestクラスのメンバ変数Nameの値で昇順に並び替えています。

数学にグループ分けされた要素の並び順が変わっています。

まとめ

ここでは、LINQのGroupByメソッドやOrderByメソッドについて説明しました。コレクションの要素をグループ分けする場合に簡潔に記述することができます。使いこなすことができるように、この記事を何度も参考にして下さいね!

この記事を書いた人

熊本在住のフリープログラマ兼ライターです。C/C++/C#、Java、Python、HTML/CSS、PHPを使ってプログラミングをしています。専門は画像処理で最近は機械学習、ディープラーニングにはまっています。幅広くやってきた経験を活かしてポイントをわかりやすくお伝えしようと思います。
お問合せはこちらでも受け付けています。
info@sss-lab.com

目次