.NET MAUI Blog プログラミング

【C#入門】LINQとは?初心者向けに分かりやすく解説!

2023年3月18日

【C#入門】LINQとは?初心者向けに分かりやすく解説!



はじめに

C#を学ぶうえで、LINQという単語をよく聞くことがありますが、LINQとは一体何でしょうか?本記事では、C#初心者向けに、分かりやすくLINQについて解説します。(サンプルコードあり)

LINQとは

LINQとは、「Language-Integrated Query」の略称で、言語統合クエリのことを指します。C#では、LINQを使用することで、データソースからデータを抽出するクエリを、C#のプログラム内で記述することができます。簡単に言えば、データを取得するための専用のクエリ言語です。

LINQのメリットとデメリット

LINQのメリットは、以下の通りです。

  • プログラム内でクエリを記述できるため、コードの可読性が向上する
  • コンパイル時にクエリの検証ができるため、実行時のエラーを減らすことができる
  • 複雑なクエリを簡単に記述できる

一方で、デメリットとしては以下の点が挙げられます。

  • LINQを使うことで、パフォーマンスが低下することがある
  • データベースのような外部データソースにアクセスする場合、LINQで対応できない場合がある

LINQの基本的な使い方

LINQの基本的な使い方は、クエリ式とメソッド構文の2種類があります。クエリ式はSQLライクな記述方法で、メソッド構文はC#のメソッドチェーン形式で記述します。データソースの種類によって、どちらの方法を使用するか選択することができます。

クエリ式とメソッド構文の違い

以下のサンプルコードを通じて、両者の違いを説明してみます。

// データソースの準備
List<int> numbers = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

// クエリ式
var querySyntax = from n in numbers
                  where n % 2 == 0
                  orderby n descending
                  select n;

// メソッド構文
var methodSyntax = numbers.Where(n => n % 2 == 0)
                          .OrderByDescending(n => n);

// 結果の出力
foreach (var number in querySyntax)
{
    Console.WriteLine(number);
}

foreach (var number in methodSyntax)
{
    Console.WriteLine(number);
}

このコードでは、numbersリストから偶数をフィルタリングし、降順にソートしています。そして、クエリ式とメソッド構文を使って同じ結果を取得しています。

「クエリ式」は、SQLのような文法で記述されたLINQです。クエリ式では、データソース(ここではnumbersリスト)から抽出するデータを指定する「from」句、データのフィルタリング条件を指定する「where」句、データのソート条件を指定する「orderby」句、そして出力するデータを指定する「select」句を使用します。

一方、「メソッド構文」は、オブジェクトのメソッドを使用してLINQを記述する方法です。メソッド構文では、メソッドのチェーンを使用してデータのフィルタリング、ソート、出力を指定します。

両者の違いは、記述方法だけでなく、コンパイル時の実行速度や可読性にも影響します。クエリ式はSQLのような文法で記述されているため、SQLに慣れ親しんでいる人には分かりやすい場合があります。一方、メソッド構文は、データ処理の流れが直感的に理解しやすく、実行速度も若干高速である場合があります。

LINQでできること

また、LINQでできることとしては、以下のようなことが挙げられます。

  • データのフィルタリング
  • ソート
  • グループ化
  • 結合
  • 集計

データのフィルタリングの例

例えば、int型の配列numbersから、値が10以上の数だけを抽出してみましょう。

int[] numbers = { 5, 10, 15, 20, 25 };

// 値が10以上の数だけを抽出
var query = from num in numbers
            where num >= 10
            select num;

foreach (var num in query)
{
    Console.WriteLine(num);
}

このコードでは、LINQのクエリ式を用いて、numbers配列からnum変数に格納された値が10以上の数だけを抽出しています。クエリ式中のwhere句で条件を指定し、select句で抽出する要素を指定しています。

実行結果は以下の通りです。

10
15
20
25

このように、LINQを用いることで、複雑な条件を指定してデータのフィルタリングを行うことができます。

ソートの例

例えば、文字列型の配列fruitsをアルファベット順に並び替えてみましょう。

string[] fruits = { "apple", "orange", "banana", "grape" };

// アルファベット順に並び替え
var query = from fruit in fruits
            orderby fruit
            select fruit;

foreach (var fruit in query)
{
    Console.WriteLine(fruit);
}

このコードでは、LINQのクエリ式を用いて、fruits配列の要素をアルファベット順に並び替えています。クエリ式中のorderby句で並び替える条件を指定し、select句で並び替えた結果を返します。

実行結果は以下の通りです。

apple
banana
grape
orange

このように、LINQを用いることで、複雑な条件を指定してデータのソートを行うことができます。また、複数の条件でソートすることも可能です。

例えば、以下のようなPersonクラスを定義し、複数の条件でソートしてみましょう。

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }
}

このクラスを使って、LastNameでまずアルファベット順にソートし、LastNameが同じ場合はFirstNameでアルファベット順にソートし、FirstNameも同じ場合はAgeで昇順にソートするコードは以下のようになります。

Person[] people = {
    new Person { FirstName = "Alice", LastName = "Smith", Age = 25 },
    new Person { FirstName = "Bob", LastName = "Johnson", Age = 30 },
    new Person { FirstName = "Charlie", LastName = "Smith", Age = 20 },
    new Person { FirstName = "Dave", LastName = "Wilson", Age = 35 },
};

// LastNameでまずアルファベット順にソートし、LastNameが同じ場合はFirstNameでアルファベット順にソートし、FirstNameも同じ場合はAgeで昇順にソートする
var query = from person in people
            orderby person.LastName, person.FirstName, person.Age
            select person;

foreach (var person in query)
{
    Console.WriteLine($"{person.LastName} {person.FirstName}, Age {person.Age}");
}

このコードでは、LINQのクエリ式を用いて、people配列の要素を3つの条件でソートしています。orderby句で、まずLastName、次にFirstName、最後にAgeの順でソートすることを指定しています。

実行結果は以下の通りです。

Johnson Bob, Age 30
Smith Alice, Age 25
Smith Charlie, Age 20
Wilson Dave, Age 35

このように、複数の条件でソートすることで、より複雑な並び順でデータを取り扱うことができます。



グループ化の例

例えば、以下のようにPersonクラスを定義し、年齢別にグループ化いてみましょう。

Person[] people = {
    new Person { Name = "Alice", Age = 25 },
    new Person { Name = "Bob", Age = 30 },
    new Person { Name = "Charlie", Age = 20 },
    new Person { Name = "Dave", Age = 35 },
    new Person { Name = "Eve", Age = 25 },
};

var groups = from person in people
             group person by person.Age into ageGroup
             orderby ageGroup.Key
             select ageGroup;

foreach (var ageGroup in groups)
{
    Console.WriteLine($"Age: {ageGroup.Key}");

    foreach (var person in ageGroup)
    {
        Console.WriteLine($"\t{person.Name}");
    }
}

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

このコードでは、LINQのクエリ式を用いて、people配列の要素を年齢別にグループ化しています。group by句で、person.Ageをキーにしてグループ化することを指定しています。また、orderby句でグループのキーである年齢でソートしています。

実行結果は以下の通りです。

Age: 20
        Charlie
Age: 25
        Alice
        Eve
Age: 30
        Bob
Age: 35
        Dave

このように、group by句を使ってデータをグループ化することで、特定のキーに基づいてデータを分類し、処理することができます。

結合の例

例えば、以下のように2つのクラスOrderCustomerを定義し、Joinメソッドを使ってorderscustomersのテーブルを結合してみましょう。

List<Order> orders = new List<Order>()
{
    new Order { OrderID = 1, ProductName = "Product1", Quantity = 10, CustomerID = 1 },
    new Order { OrderID = 2, ProductName = "Product2", Quantity = 5, CustomerID = 2 },
    new Order { OrderID = 3, ProductName = "Product3", Quantity = 3, CustomerID = 3 },
};

List<Customer> customers = new List<Customer>()
{
    new Customer { CustomerID = 1, CustomerName = "Customer1" },
    new Customer { CustomerID = 2, CustomerName = "Customer2" },
    new Customer { CustomerID = 3, CustomerName = "Customer3" },
};

var query = from order in orders
            join customer in customers
            on order.CustomerID equals customer.CustomerID
            select new { OrderID = order.OrderID, ProductName = order.ProductName, Quantity = order.Quantity, CustomerName = customer.CustomerName };

foreach (var item in query)
{
    Console.WriteLine($"OrderID: {item.OrderID}, ProductName: {item.ProductName}, Quantity: {item.Quantity}, CustomerName: {item.CustomerName}");
}

public class Order
{
    public int OrderID { get; set; }
    public string ProductName { get; set; }
    public int Quantity { get; set; }
    public int CustomerID { get; set; }
}

public class Customer
{
    public int CustomerID { get; set; }
    public string CustomerName { get; set; }
}

このコードでは、Joinメソッドを使って、orderscustomersのテーブルをCustomerIDで結合しています。結合する際に、select句で新しい匿名型オブジェクトを作成し、必要な情報を取得しています。

実行結果は以下の通りです。

OrderID: 1, ProductName: Product1, Quantity: 10, CustomerName: Customer1
OrderID: 2, ProductName: Product2, Quantity: 5, CustomerName: Customer2
OrderID: 3, ProductName: Product3, Quantity: 3, CustomerName: Customer3

このように、Joinメソッドを使って複数のテーブルを結合することで、必要な情報を結合して取得することができます。

集計の例

以下の例では、整数のリストに対してSumAverageMinMaxの集計関数を使って集計を行っています。

List<int> numbers = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

int sum = numbers.Sum();
double average = numbers.Average();
int min = numbers.Min();
int max = numbers.Max();

Console.WriteLine($"Sum: {sum}, Average: {average}, Min: {min}, Max: {max}");

このコードでは、Sumメソッドを使ってnumbersリストの合計、Averageメソッドを使って平均、Minメソッドを使って最小値、Maxメソッドを使って最大値を計算しています。

実行結果は以下の通りです。

Sum: 55, Average: 5.5, Min: 1, Max: 10

このように、LINQでは集計関数を使って、リストやテーブルの値を簡単に集計することができます。また、複数の集計関数を組み合わせて、必要な情報を取得することもできます。

LINQの応用例

LINQは、データベースからのデータ取得や、ファイルからのデータ読み込み、XMLファイルの処理など、様々な応用が可能です。例えば、データベースからのデータ取得には、Entity Frameworkというフレームワークが使用されることがあります。また、XMLファイルの処理には、LINQ to XMLという技術が使用されます。これらの応用例を把握することで、C#プログラミングの幅が広がります。

まとめ

LINQは、C#プログラミングにおいて、データソースからデータを抽出するための専用のクエリ言語です。プログラム内でクエリを記述できるため、可読性が向上し、コンパイル時に検証ができるためエラーを減らすことができます。ただし、パフォーマンス低下や外部データソースへのアクセスができない場合があるため、注意が必要です。基本的な使い方や応用例を学ぶことで、C#プログラミングの幅を広げることができます。



-.NET MAUI, Blog, プログラミング
-