C# LINQの使い方を基礎から実践まで解説|Where・Select・OrderByがわかる入門ガイド

はじめに

C#で配列やList、オブジェクトの一覧を扱うときに便利なのが LINQ です。LINQを使うと、データの検索、抽出、変換、並び替え、集計などを短く読みやすいコードで書けます。

たとえば、年齢が20歳以上のユーザーだけを取り出したい場合、foreachで1件ずつ条件判定を書くこともできますが、LINQなら次のように書けます。

C#
var adults = users.Where(user => user.Age >= 20);

このように、C# LINQを使うと「何をしたいか」がコードからわかりやすくなります。

この記事では、C# LINQの基本から、よく使う WhereSelectOrderBy、さらに FirstAnyGroupByToList などの便利なメソッドまで、初心者にもわかりやすく解説します。

1. C# LINQとは?基礎からわかる概要

1-1. LINQの意味と読み方

LINQは Language Integrated Query の略です。読み方は「リンク」です。

日本語にすると「言語に統合された問い合わせ機能」という意味になります。C#のコードの中で、配列やList、データベース、XMLなどに対して、SQLのような感覚でデータ操作を行える仕組みです。

C# LINQでは、主に次のような操作ができます。

C#
var result = numbers.Where(n => n >= 10);

このコードは、numbers の中から10以上の値だけを取り出しています。

LINQを使うには、基本的に次の名前空間を使用します。

C#
using System.Linq;

最近のC#プロジェクトでは最初から使えることも多いですが、LINQメソッドが認識されない場合は using System.Linq; があるか確認しましょう。

1-2. LINQでできること

LINQを使うと、コレクションに対してさまざまな処理を簡単に書けます。

代表的な処理は次のとおりです。

処理使用する主なメソッド
条件に合うデータを抽出するWhere
必要な項目だけ取り出すSelect
データを並び替えるOrderBy / OrderByDescending
最初の1件を取得するFirst / FirstOrDefault
件数を数えるCount
合計や平均を求めるSum / Average
グループ化するGroupBy
重複を除くDistinct
一部だけ取得するTake / Skip

たとえば、商品の一覧から価格が1000円以上の商品名だけを取り出す場合は、次のように書けます。

C#
var names = products
.Where(product => product.Price >= 1000)
.Select(product => product.Name);

Where で条件に合う商品を抽出し、Select で商品名だけを取り出しています。

1-3. LINQを使うメリット

LINQを使う主なメリットは、コードが短く、読みやすく、意図が伝わりやすくなることです。

foreachで書くと、次のようになります。

C#
var result = new List<int>();

foreach (var number in numbers)
{
if (number >= 10)
{
result.Add(number);
}
}

LINQを使うと、同じ処理を次のように書けます。

C#
var result = numbers.Where(number => number >= 10).ToList();

LINQのメリットは次のとおりです。

メリット内容
コードが短くなる条件抽出や変換を簡潔に書ける
意図がわかりやすいWhere、Select、OrderByなどの名前から処理内容が伝わる
処理を組み合わせやすい抽出、変換、並び替えを連続して書ける
配列やListに同じ感覚で使えるさまざまなコレクションに対応できる
保守しやすい処理の流れを追いやすい

ただし、LINQを使いすぎると逆に読みにくくなることもあります。複雑な処理では、無理に1行で書かず、変数に分けることも大切です。

1-4. foreachやSQLとの違い

LINQは、foreachやSQLと似た場面で使われますが、それぞれ役割が異なります。

foreachは、コレクションを1件ずつ処理するための構文です。

C#
foreach (var item in items)
{
Console.WriteLine(item);
}

一方、LINQは「条件に合うデータを取り出す」「並び替える」「別の形に変換する」といったデータ操作を簡潔に書くための機能です。

C#
var result = items.Where(item => item.IsActive);

SQLは、主にデータベースに対して問い合わせを行う言語です。

SQL
SELECT * FROM Users WHERE Age >= 20;

LINQでは、C#のコード内で似たような考え方を使えます。

C#
var adults = users.Where(user => user.Age >= 20);

違いを整理すると、次のようになります。

種類主な用途
foreach1件ずつ順番に処理する
LINQコレクションを抽出・変換・並び替えする
SQLデータベースに問い合わせる

LINQはSQLのような考え方をC#の中で使える機能ですが、SQLそのものではありません。C#の文法として書けるため、型チェックや補完が効く点が大きな特徴です。

1-5. LINQがよく使われる場面

C# LINQは、実務でも非常によく使われます。

たとえば、次のような場面です。

場面
配列やListの検索IDが一致するユーザーを探す
条件抽出有効なデータだけを取り出す
表示用データの作成必要な項目だけ取り出す
並び替え名前順、日付順、金額順に並べる
集計合計金額、平均点、件数を求める
重複除去同じカテゴリ名を1つにまとめる
ページング一覧画面で10件ずつ表示する

特に、Webアプリケーションや業務システムでは、データの一覧を扱う場面が多いため、LINQを使えるとコードがかなり書きやすくなります。

2. LINQを使う前に知っておきたい基本構文

2-1. メソッド構文とクエリ構文の違い

LINQには大きく分けて、次の2種類の書き方があります。

1つ目は メソッド構文 です。

C#
var result = numbers.Where(n => n >= 10);

2つ目は クエリ構文 です。

C#
var result =
from n in numbers
where n >= 10
select n;

どちらも同じ意味です。

メソッド構文は、WhereSelectOrderBy などのメソッドをつなげて書きます。C# LINQでは、このメソッド構文がよく使われます。

クエリ構文はSQLに近い見た目で書けるため、SQLに慣れている人には読みやすい場合があります。

比較すると、次のようになります。

書き方特徴
メソッド構文実務でよく使われる。メソッドをつなげて書く
クエリ構文SQLに近い見た目で書ける

この記事では、実務でよく使われるメソッド構文を中心に解説します。

2-2. ラムダ式の基本

LINQでは、ラムダ式をよく使います。

ラムダ式とは、簡単にいうと「処理を短く書くための記法」です。

C#
n => n >= 10

これは、「nを受け取って、nが10以上かどうかを返す」という意味です。

たとえば、次のLINQを見てみましょう。

C#
var result = numbers.Where(n => n >= 10);

この中の n => n >= 10 がラムダ式です。

分解すると、次のようになります。

部分意味
nコレクション内の1つの要素
=>左を受け取って右の処理を行う
n >= 10条件式

オブジェクトの場合は、次のように書きます。

C#
var adults = users.Where(user => user.Age >= 20);

この場合、userusers の中にある1件のユーザーを表しています。

ラムダ式の変数名は自由に決められます。

C#
var adults = users.Where(x => x.Age >= 20);

ただし、x よりも user のように意味のある名前を使った方が、読みやすいコードになります。

2-3. IEnumerableとIQueryableの違い

LINQを学ぶと、IEnumerableIQueryable という言葉が出てきます。

初心者のうちは難しく感じるかもしれませんが、まずは次のように理解するとよいでしょう。

主な用途
IEnumerableメモリ上のコレクションを扱う
IQueryableデータベースなど外部データソースへの問い合わせを扱う

IEnumerable は、配列やListなど、すでにメモリ上にあるデータを扱うときによく使われます。

C#
IEnumerable<int> numbers = new List<int> { 1, 2, 3, 4, 5 };

var result = numbers.Where(n => n >= 3);

IQueryable は、Entity Frameworkなどでデータベースに問い合わせるときによく使われます。

C#
IQueryable<User> users = dbContext.Users;

var adults = users.Where(user => user.Age >= 20);

IQueryable の場合、LINQで書いた処理がSQLなどに変換されて実行されることがあります。

初心者がまず覚えるべきポイントは、配列やListを扱うなら基本的には IEnumerable のLINQを理解すれば十分ということです。

2-4. 遅延実行と即時実行

LINQでは、非常に重要な考え方として 遅延実行 があります。

遅延実行とは、LINQを書いた時点では処理が実行されず、実際に結果が必要になったタイミングで実行される仕組みです。

たとえば、次のコードを見てください。

C#
var numbers = new List<int> { 1, 2, 3, 4, 5 };

var result = numbers.Where(n => n >= 3);

numbers.Add(6);

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

出力結果は次のようになります。

3
4
5
6

Where を書いた時点ではまだ抽出処理は実行されていません。foreach で結果を使うタイミングで実行されるため、後から追加した 6 も結果に含まれます。

一方、ToListToArray を使うと、その時点で処理が実行されます。これを 即時実行 といいます。

C#
var result = numbers.Where(n => n >= 3).ToList();

ToList を使うと、その時点の結果がListとして確定します。

主な即時実行のメソッドには、次のようなものがあります。

メソッド内容
ToListListに変換する
ToArray配列に変換する
Count件数を数える
First最初の1件を取得する
Sum合計を求める
Average平均を求める

LINQでは、遅延実行と即時実行の違いを理解しておくことがとても大切です。

2-5. サンプルデータを使ったLINQの基本形

この記事では、次のようなサンプルデータを使って解説します。

C#
public class User
{
public int Id { get; set; }
public string Name { get; set; } = "";
public int Age { get; set; }
public string Department { get; set; } = "";
public int Score { get; set; }
}

サンプルのユーザー一覧です。

C#
var users = new List<User>
{
new User { Id = 1, Name = "田中", Age = 25, Department = "営業", Score = 80 },
new User { Id = 2, Name = "佐藤", Age = 32, Department = "開発", Score = 95 },
new User { Id = 3, Name = "鈴木", Age = 19, Department = "営業", Score = 70 },
new User { Id = 4, Name = "高橋", Age = 41, Department = "人事", Score = 88 },
new User { Id = 5, Name = "伊藤", Age = 28, Department = "開発", Score = 76 }
};

LINQの基本形は次のようになります。

C#
var result = users.Where(user => user.Age >= 20);

このコードは、20歳以上のユーザーを抽出しています。

さらに名前だけ取り出す場合は、Select を使います。

C#
var names = users
.Where(user => user.Age >= 20)
.Select(user => user.Name);

年齢順に並び替える場合は、OrderBy を使います。

C#
var sortedUsers = users.OrderBy(user => user.Age);

このように、LINQはメソッドを組み合わせて使うことで、さまざまなデータ操作ができます。

3. Whereの使い方|条件に合うデータを抽出する

3-1. Whereの基本構文

Where は、条件に合うデータだけを抽出するためのLINQメソッドです。

基本構文は次のとおりです。

C#
var result = collection.Where(item => 条件式);

たとえば、数値の一覧から3以上の値だけを取り出す場合は、次のように書きます。

C#
var numbers = new List<int> { 1, 2, 3, 4, 5 };

var result = numbers.Where(number => number >= 3);

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

出力結果は次のようになります。

3
4
5

Where のラムダ式には、trueまたはfalseを返す条件式を書きます。条件がtrueになった要素だけが結果に含まれます。

3-2. 数値条件で絞り込む方法

数値条件で絞り込む場合は、比較演算子を使います。

C#
var adults = users.Where(user => user.Age >= 20);

このコードは、20歳以上のユーザーを抽出します。

点数が80点以上のユーザーを取得する場合は、次のように書きます。

C#
var highScoreUsers = users.Where(user => user.Score >= 80);

比較演算子には、次のようなものがあります。

演算子意味
==等しい
!=等しくない
>より大きい
>=以上
<より小さい
<=以下

たとえば、30歳未満のユーザーを取得する場合は次のようになります。

C#
var youngUsers = users.Where(user => user.Age < 30);

特定のIDに一致するユーザーを探す場合は、次のように書きます。

C#
var targetUsers = users.Where(user => user.Id == 3);

ただし、1件だけ取得したい場合は、Where よりも FirstOrDefault を使うことが多いです。

C#
var user = users.FirstOrDefault(user => user.Id == 3);

3-3. 文字列条件で絞り込む方法

文字列を条件にする場合は、==ContainsStartsWithEndsWith などを使います。

部署が「開発」のユーザーだけを取得する例です。

C#
var developers = users.Where(user => user.Department == "開発");

名前に「田」が含まれるユーザーを取得する場合は、Contains を使います。

C#
var result = users.Where(user => user.Name.Contains("田"));

名前が「佐」で始まるユーザーを取得する場合は、StartsWith を使います。

C#
var result = users.Where(user => user.Name.StartsWith("佐"));

名前が「橋」で終わるユーザーを取得する場合は、EndsWith を使います。

C#
var result = users.Where(user => user.Name.EndsWith("橋"));

文字列条件で注意したいのは、対象の文字列が null の可能性がある場合です。

C#
var result = users.Where(user => user.Name != null && user.Name.Contains("田"));

C#のnull条件演算子を使うと、次のようにも書けます。

C#
var result = users.Where(user => user.Name?.Contains("田") == true);

3-4. 複数条件を指定する方法

Where では、複数条件も指定できます。

AND条件には && を使います。

C#
var result = users.Where(user => user.Age >= 20 && user.Department == "開発");

このコードは、20歳以上かつ部署が開発のユーザーを抽出します。

OR条件には || を使います。

C#
var result = users.Where(user => user.Department == "営業" || user.Department == "開発");

このコードは、部署が営業または開発のユーザーを抽出します。

条件が複雑な場合は、複数の Where をつなげることもできます。

C#
var result = users
.Where(user => user.Age >= 20)
.Where(user => user.Department == "開発");

これは次のコードと同じ意味です。

C#
var result = users.Where(user => user.Age >= 20 && user.Department == "開発");

どちらを使っても問題ありません。条件ごとに意味を分けたい場合は、複数の Where をつなげると読みやすくなることがあります。

3-5. Whereでよくあるエラーと注意点

Where でよくある注意点の1つは、結果が1件もない場合でもエラーにはならないことです。

C#
var result = users.Where(user => user.Age >= 100);

この場合、条件に合うユーザーがいなければ、空の結果が返ります。

ただし、その後に First を使うとエラーになることがあります。

C#
var user = users.Where(user => user.Age >= 100).First();

条件に合うデータが1件もない場合、First は例外を発生させます。見つからない可能性がある場合は、FirstOrDefault を使いましょう。

C#
var user = users.FirstOrDefault(user => user.Age >= 100);

if (user != null)
{
Console.WriteLine(user.Name);
}

また、Where は遅延実行されます。次のようなコードでは、result を作った後に元のListを変更すると、結果にも影響します。

C#
var result = users.Where(user => user.Age >= 20);

users.Add(new User { Id = 6, Name = "山本", Age = 35, Department = "営業", Score = 82 });

foreach (var user in result)
{
Console.WriteLine(user.Name);
}

結果をその時点で固定したい場合は、ToList を使います。

C#
var result = users.Where(user => user.Age >= 20).ToList();

4. Selectの使い方|必要なデータだけを取り出す

4-1. Selectの基本構文

Select は、コレクションの各要素を別の形に変換するためのLINQメソッドです。

基本構文は次のとおりです。

C#
var result = collection.Select(item => 変換後の値);

たとえば、ユーザー一覧から名前だけを取り出す場合は、次のように書きます。

C#
var names = users.Select(user => user.Name);

この結果は、ユーザーオブジェクトの一覧ではなく、名前の一覧になります。

C#
foreach (var name in names)
{
Console.WriteLine(name);
}

出力例は次のようになります。

田中
佐藤
鈴木
高橋
伊藤

Where が「条件に合うデータを選ぶ」のに対して、Select は「データの形を変える」ために使います。

4-2. プロパティだけを取り出す方法

オブジェクトの一覧から特定のプロパティだけを取り出す場合、Select を使います。

名前だけを取り出す例です。

C#
var names = users.Select(user => user.Name);

年齢だけを取り出す例です。

C#
var ages = users.Select(user => user.Age);

部署だけを取り出す例です。

C#
var departments = users.Select(user => user.Department);

重複を除いた部署一覧を取得したい場合は、Distinct と組み合わせます。

C#
var departments = users
.Select(user => user.Department)
.Distinct();

画面表示やCSV出力などで、オブジェクト全体ではなく一部の項目だけ必要な場合に Select はよく使われます。

4-3. 匿名型に変換する方法

Select では、複数のプロパティをまとめて新しい形に変換できます。

たとえば、名前と部署だけを取り出したい場合は、匿名型を使います。

C#
var result = users.Select(user => new
{
user.Name,
user.Department
});

この結果は、NameDepartment だけを持つデータの一覧になります。

C#
foreach (var item in result)
{
Console.WriteLine($"{item.Name} - {item.Department}");
}

プロパティ名を変えることもできます。

C#
var result = users.Select(user => new
{
UserName = user.Name,
Dept = user.Department
});

匿名型は、画面表示用や一時的なデータ加工に便利です。

ただし、メソッドの戻り値として使い回す場合は、匿名型ではなくDTOや専用クラスを作る方がわかりやすいです。

C#
public class UserSummary
{
public string Name { get; set; } = "";
public string Department { get; set; } = "";
}
C#
var result = users.Select(user => new UserSummary
{
Name = user.Name,
Department = user.Department
});

4-4. Selectでデータを加工する方法

Select では、値をそのまま取り出すだけでなく、加工して返すこともできます。

たとえば、名前に敬称を付ける例です。

C#
var displayNames = users.Select(user => user.Name + "さん");

年齢から区分を作ることもできます。

C#
var result = users.Select(user => new
{
user.Name,
Category = user.Age >= 20 ? "成人" : "未成年"
});

点数に応じて合否を判定する例です。

C#
var result = users.Select(user => new
{
user.Name,
user.Score,
Result = user.Score >= 80 ? "合格" : "不合格"
});

文字列を整形する場合にも便利です。

C#
var messages = users.Select(user => $"{user.Name}さんは{user.Department}所属です");

Select は、元データを表示用の形に変換するときに特によく使います。

4-5. SelectとWhereを組み合わせる方法

WhereSelect は、LINQで特によく組み合わせて使います。

たとえば、20歳以上のユーザーの名前だけを取得する場合は、次のように書きます。

C#
var names = users
.Where(user => user.Age >= 20)
.Select(user => user.Name);

処理の流れは次のとおりです。

  1. Where で20歳以上のユーザーを抽出する

  2. Select で名前だけを取り出す

開発部門のユーザーを表示用データに変換する例です。

C#
var result = users
.Where(user => user.Department == "開発")
.Select(user => new
{
user.Name,
user.Score
});

WhereSelect の順番も重要です。

一般的には、先に Where で件数を絞ってから Select で変換します。

C#
var result = users
.Where(user => user.Score >= 80)
.Select(user => new
{
user.Name,
user.Score
});

先に不要なデータを減らすことで、後続の処理がわかりやすくなります。

5. OrderByの使い方|データを並び替える

5-1. OrderByの基本構文

OrderBy は、データを昇順に並び替えるためのLINQメソッドです。

基本構文は次のとおりです。

C#
var result = collection.OrderBy(item => 並び替えに使う値);

たとえば、数値を小さい順に並び替える場合は、次のように書きます。

C#
var numbers = new List<int> { 5, 1, 4, 2, 3 };

var result = numbers.OrderBy(number => number);

出力結果は次のようになります。

1
2
3
4
5

ユーザーを年齢順に並び替える場合は、次のように書きます。

C#
var sortedUsers = users.OrderBy(user => user.Age);

OrderBy は元のList自体を並び替えるのではなく、並び替えた結果を返します。

C#
var sortedUsers = users.OrderBy(user => user.Age).ToList();

元のListを変更したい場合は、結果を新しいListとして受け取るのが一般的です。

5-2. 昇順で並び替える方法

OrderBy は昇順で並び替えます。

数値の場合は、小さい順です。

C#
var sortedUsers = users.OrderBy(user => user.Age);

文字列の場合は、文字列の並び順でソートされます。

C#
var sortedUsers = users.OrderBy(user => user.Name);

点数の低い順に並べる場合は、次のようになります。

C#
var sortedUsers = users.OrderBy(user => user.Score);

並び替えた結果をすぐに表示する例です。

C#
foreach (var user in users.OrderBy(user => user.Age))
{
Console.WriteLine($"{user.Name}: {user.Age}");
}

LINQの OrderBy は、一覧画面で「日付が古い順」「名前順」「価格が安い順」などを実装するときによく使います。

5-3. 降順で並び替えるOrderByDescending

降順で並び替える場合は、OrderByDescending を使います。

C#
var sortedUsers = users.OrderByDescending(user => user.Age);

このコードは、年齢が高い順にユーザーを並び替えます。

点数が高い順に並び替える例です。

C#
var ranking = users.OrderByDescending(user => user.Score);

出力例です。

C#
foreach (var user in ranking)
{
Console.WriteLine($"{user.Name}: {user.Score}");
}

日付を新しい順に並べたい場合も、OrderByDescending を使います。

C#
var latestOrders = orders.OrderByDescending(order => order.CreatedAt);

一覧画面では、登録日や更新日を新しい順に表示することが多いため、OrderByDescending は実務でもよく使われます。

5-4. ThenByで複数条件の並び替えをする方法

複数条件で並び替えたい場合は、ThenBy を使います。

たとえば、部署順に並べた後、同じ部署内では年齢順に並べる例です。

C#
var sortedUsers = users
.OrderBy(user => user.Department)
.ThenBy(user => user.Age);

降順の追加条件には、ThenByDescending を使います。

C#
var sortedUsers = users
.OrderBy(user => user.Department)
.ThenByDescending(user => user.Score);

このコードは、部署順に並べた後、同じ部署内では点数が高い順に並べます。

注意点として、2つ目以降の並び替えに再び OrderBy を使うと、前の並び替え条件が上書きされてしまいます。

C#
var wrong = users
.OrderBy(user => user.Department)
.OrderBy(user => user.Age);

この場合、最終的には年齢順の並び替えが優先され、部署順の意味が薄れてしまいます。

複数条件で並び替える場合は、次のように ThenBy を使いましょう。

C#
var correct = users
.OrderBy(user => user.Department)
.ThenBy(user => user.Age);

5-5. 並び替えでnullを扱うときの注意点

並び替え対象の値が null になる可能性がある場合は注意が必要です。

たとえば、名前が null のデータが含まれている場合でも、OrderBy 自体は動作します。

C#
var sortedUsers = users.OrderBy(user => user.Name);

ただし、並び替え前に文字列メソッドを呼び出す場合は、null参照エラーになることがあります。

C#
var sortedUsers = users.OrderBy(user => user.Name.ToLower());

Namenull の場合、ToLower() を呼び出せずエラーになります。

対策として、null合体演算子 ?? を使います。

C#
var sortedUsers = users.OrderBy(user => user.Name ?? "");

nullを最後にしたい場合は、次のように書くこともできます。

C#
var sortedUsers = users
.OrderBy(user => user.Name == null)
.ThenBy(user => user.Name);

user.Name == null が false のデータが先に並び、nullのデータが後ろになります。

6. LINQでよく使う便利なメソッド

6-1. First・FirstOrDefaultの使い方

First は、条件に合う最初の要素を取得するメソッドです。

C#
var user = users.First(user => user.Age >= 20);

このコードは、20歳以上の最初のユーザーを取得します。

ただし、条件に合うデータが1件もない場合、First は例外を発生させます。

C#
var user = users.First(user => user.Age >= 100);

このような場合は、FirstOrDefault を使うと安全です。

C#
var user = users.FirstOrDefault(user => user.Age >= 100);

if (user == null)
{
Console.WriteLine("該当するユーザーはいません");
}

FirstOrDefault は、条件に合うデータがない場合に既定値を返します。参照型の場合は null が返ります。

使い分けは次のとおりです。

メソッド条件に合うデータがない場合
First例外が発生する
FirstOrDefault既定値を返す

基本的には、見つからない可能性がある検索では FirstOrDefault を使うと安全です。

6-2. Any・Allの使い方

Any は、条件に合う要素が1件でもあるかを調べるメソッドです。

C#
bool exists = users.Any(user => user.Age >= 20);

このコードは、20歳以上のユーザーが1人でもいれば true を返します。

条件を指定しない場合は、コレクションに要素があるかどうかを確認できます。

C#
bool hasUsers = users.Any();

All は、すべての要素が条件を満たすかを調べるメソッドです。

C#
bool allAdults = users.All(user => user.Age >= 20);

このコードは、すべてのユーザーが20歳以上なら true を返します。

使い分けは次のとおりです。

メソッド意味
Any1件でも条件を満たすか
Allすべて条件を満たすか

データの存在確認には、Count() > 0 よりも Any() を使う方が意図が明確です。

C#
if (users.Any())
{
Console.WriteLine("ユーザーが存在します");
}

6-3. Count・Sum・Averageの使い方

Count は、件数を数えるメソッドです。

C#
int count = users.Count();

条件を指定することもできます。

C#
int adultCount = users.Count(user => user.Age >= 20);

Sum は合計を求めます。

C#
int totalScore = users.Sum(user => user.Score);

Average は平均を求めます。

C#
double averageScore = users.Average(user => user.Score);

部署が開発のユーザーの平均点を求める例です。

C#
double averageScore = users
.Where(user => user.Department == "開発")
.Average(user => user.Score);

ただし、空のコレクションに対して Average を使うと例外が発生します。

C#
var targetUsers = users.Where(user => user.Department == "存在しない部署");

if (targetUsers.Any())
{
double average = targetUsers.Average(user => user.Score);
Console.WriteLine(average);
}

空になる可能性がある場合は、先に Any で確認すると安全です。

6-4. GroupByの使い方

GroupBy は、指定したキーごとにデータをグループ化するメソッドです。

部署ごとにユーザーをまとめる例です。

C#
var groups = users.GroupBy(user => user.Department);

グループ化した結果を表示する例です。

C#
foreach (var group in groups)
{
Console.WriteLine($"部署: {group.Key}");

foreach (var user in group)
{
Console.WriteLine($" {user.Name}");
}
}

group.Key には、グループ化に使った値が入ります。この例では部署名です。

部署ごとの人数を取得する場合は、Select と組み合わせます。

C#
var result = users
.GroupBy(user => user.Department)
.Select(group => new
{
Department = group.Key,
Count = group.Count()
});

部署ごとの平均点を求めることもできます。

C#
var result = users
.GroupBy(user => user.Department)
.Select(group => new
{
Department = group.Key,
AverageScore = group.Average(user => user.Score)
});

GroupBy は、集計処理やレポート作成でよく使われます。

6-5. Distinctの使い方

Distinct は、重複を除いた一覧を取得するメソッドです。

数値の重複を除く例です。

C#
var numbers = new List<int> { 1, 2, 2, 3, 3, 3 };

var result = numbers.Distinct();

出力結果は次のようになります。

1
2
3

ユーザー一覧から重複しない部署名を取得する場合は、Select と組み合わせます。

C#
var departments = users
.Select(user => user.Department)
.Distinct();

注意点として、オブジェクトに対してそのまま Distinct を使う場合、期待どおりに重複除去されないことがあります。

C#
var distinctUsers = users.Distinct();

オブジェクトの重複判定は、既定では参照が同じかどうかで判断されます。特定のプロパティで重複を除きたい場合は、対象のプロパティを Select するか、DistinctBy を使います。

C#
var uniqueDepartments = users.DistinctBy(user => user.Department);

DistinctBy を使うと、指定したキーに基づいて重複を除けます。

6-6. Take・Skipの使い方

Take は、先頭から指定した件数だけ取得するメソッドです。

C#
var top3 = users.Take(3);

このコードは、先頭から3件のユーザーを取得します。

Skip は、先頭から指定した件数を飛ばすメソッドです。

C#
var result = users.Skip(2);

このコードは、先頭2件を飛ばして、それ以降のユーザーを取得します。

TakeSkip は、ページング処理でよく使います。

たとえば、1ページあたり10件表示する場合、2ページ目のデータは次のように取得できます。

C#
int page = 2;
int pageSize = 10;

var result = users
.Skip((page - 1) * pageSize)
.Take(pageSize);

3ページ目なら、次のようになります。

C#
int page = 3;
int pageSize = 10;

var result = users
.Skip((page - 1) * pageSize)
.Take(pageSize);

一覧画面や検索結果のページングでは、SkipTake の組み合わせがよく使われます。

6-7. ToList・ToArrayの使い方

ToList は、LINQの結果をListに変換するメソッドです。

C#
var result = users
.Where(user => user.Age >= 20)
.ToList();

ToArray は、配列に変換するメソッドです。

C#
var result = users
.Where(user => user.Age >= 20)
.ToArray();

LINQの WhereSelect は遅延実行されるため、結果をその時点で確定したい場合に ToListToArray を使います。

たとえば、次のコードでは result はListになります。

C#
List<User> result = users
.Where(user => user.Age >= 20)
.ToList();

配列として扱いたい場合は、次のようにします。

C#
User[] result = users
.Where(user => user.Age >= 20)
.ToArray();

ただし、必要がないのに何度も ToList を使うと、余分なメモリを使うことがあります。

C#
var result = users
.Where(user => user.Age >= 20)
.ToList()
.Where(user => user.Score >= 80)
.ToList();

このように途中で何度もList化するより、最後に1回だけ ToList する方が自然です。

C#
var result = users
.Where(user => user.Age >= 20)
.Where(user => user.Score >= 80)
.ToList();

7. LINQの実践例|配列・List・オブジェクトを操作する

7-1. 配列にLINQを使う例

LINQはListだけでなく、配列にも使えます。

C#
int[] numbers = { 5, 1, 8, 3, 10, 2 };

var result = numbers
.Where(number => number >= 5)
.OrderBy(number => number);

このコードは、5以上の数値を抽出し、小さい順に並び替えます。

出力する例です。

C#
foreach (var number in result)
{
Console.WriteLine(number);
}

出力結果は次のようになります。

5
8
10

配列から偶数だけを取得する例です。

C#
var evenNumbers = numbers.Where(number => number % 2 == 0);

合計を求める例です。

C#
int total = numbers.Sum();

平均を求める例です。

C#
double average = numbers.Average();

このように、配列に対してもLINQを使うことで、数値の抽出や集計を簡単に書けます。

7-2. ListにLINQを使う例

Listに対してLINQを使う例を見てみましょう。

C#
var names = new List<string>
{
"Tanaka",
"Sato",
"Suzuki",
"Takahashi",
"Ito"
};

名前が5文字以上のものだけを取得します。

C#
var result = names.Where(name => name.Length >= 5);

アルファベット順に並び替える場合は、次のように書きます。

C#
var sortedNames = names.OrderBy(name => name);

大文字に変換する場合は、Select を使います。

C#
var upperNames = names.Select(name => name.ToUpper());

Listの中から特定の文字を含むデータを検索する例です。

C#
var result = names.Where(name => name.Contains("ta"));

ListはC#で非常によく使われるため、LINQと組み合わせる場面も多くあります。

7-3. オブジェクトの一覧から条件検索する例

実務では、単純な数値や文字列だけでなく、オブジェクトの一覧をLINQで操作することが多いです。

たとえば、商品クラスを用意します。

C#
public class Product
{
public int Id { get; set; }
public string Name { get; set; } = "";
public string Category { get; set; } = "";
public int Price { get; set; }
public bool IsActive { get; set; }
}

商品一覧です。

C#
var products = new List<Product>
{
new Product { Id = 1, Name = "ノートPC", Category = "PC", Price = 120000, IsActive = true },
new Product { Id = 2, Name = "マウス", Category = "周辺機器", Price = 3000, IsActive = true },
new Product { Id = 3, Name = "キーボード", Category = "周辺機器", Price = 8000, IsActive = false },
new Product { Id = 4, Name = "モニター", Category = "周辺機器", Price = 25000, IsActive = true }
};

販売中の商品だけを取得する例です。

C#
var activeProducts = products.Where(product => product.IsActive);

価格が10000円以上の商品を取得する例です。

C#
var expensiveProducts = products.Where(product => product.Price >= 10000);

周辺機器カテゴリの商品名だけを取得する例です。

C#
var names = products
.Where(product => product.Category == "周辺機器")
.Select(product => product.Name);

このように、オブジェクトの一覧に対してLINQを使うと、条件検索や表示用データの作成が簡単になります。

7-4. 複数のLINQメソッドをつなげる例

LINQは複数のメソッドをつなげて使うことができます。これをメソッドチェーンと呼びます。

たとえば、販売中の商品から価格が高い順に並べ、商品名と価格だけを取り出す例です。

C#
var result = products
.Where(product => product.IsActive)
.OrderByDescending(product => product.Price)
.Select(product => new
{
product.Name,
product.Price
});

処理の流れは次のとおりです。

  1. Where で販売中の商品だけを抽出する

  2. OrderByDescending で価格が高い順に並び替える

  3. Select で商品名と価格だけを取り出す

先頭2件だけを取得する場合は、Take を追加します。

C#
var result = products
.Where(product => product.IsActive)
.OrderByDescending(product => product.Price)
.Take(2)
.Select(product => new
{
product.Name,
product.Price
});

LINQメソッドをつなげるときは、1行に詰め込まず、改行して書くと読みやすくなります。

C#
var result = products
.Where(product => product.IsActive)
.Where(product => product.Price >= 5000)
.OrderBy(product => product.Price)
.Select(product => product.Name)
.ToList();

7-5. 実務で使いやすい検索・抽出・並び替えの例

実務では、検索条件が入力されている場合だけ絞り込む、という処理がよくあります。

たとえば、商品検索の例です。

C#
string? keyword = "マ";
string? category = "周辺機器";
int? minPrice = 5000;

IEnumerable<Product> query = products;

if (!string.IsNullOrWhiteSpace(keyword))
{
query = query.Where(product => product.Name.Contains(keyword));
}

if (!string.IsNullOrWhiteSpace(category))
{
query = query.Where(product => product.Category == category);
}

if (minPrice.HasValue)
{
query = query.Where(product => product.Price >= minPrice.Value);
}

var result = query
.OrderBy(product => product.Price)
.ToList();

このように、条件がある場合だけ Where を追加していく書き方は、実務で使いやすいです。

一覧画面向けに表示用データへ変換する例です。

C#
var viewModels = products
.Where(product => product.IsActive)
.OrderByDescending(product => product.Price)
.Select(product => new
{
DisplayName = $"{product.Name}({product.Category})",
PriceText = $"{product.Price:N0}円"
})
.ToList();

このコードでは、販売中の商品だけを対象にし、価格が高い順に並べたうえで、画面表示用の文字列に変換しています。

実務では、LINQを使って次のような処理をまとめることが多いです。

処理LINQメソッド
検索条件に合うデータを抽出Where
表示順を決めるOrderBy / OrderByDescending
表示用の形に変換Select
ページングするSkip / Take
結果を確定するToList

8. LINQを使うときの注意点

8-1. 遅延実行による想定外の動作

LINQの WhereSelect は、多くの場合、遅延実行されます。つまり、LINQを書いた時点では処理されず、実際に列挙されたときに実行されます。

次の例を見てください。

C#
var numbers = new List<int> { 1, 2, 3 };

var result = numbers.Where(number => number >= 2);

numbers.Add(4);

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

出力結果は次のようになります。

2
3
4

result を作った後に追加した 4 も含まれています。これは、foreach で実際に列挙したタイミングで Where が実行されるためです。

その時点の結果を固定したい場合は、ToList を使います。

C#
var result = numbers.Where(number => number >= 2).ToList();

遅延実行は便利ですが、元データが後から変わる可能性がある場合は注意しましょう。

8-2. null参照エラーへの対処

LINQでは、null参照エラーにも注意が必要です。

たとえば、次のコードは Namenull の場合にエラーになります。

C#
var result = users.Where(user => user.Name.Contains("田"));

安全に書くには、nullチェックを入れます。

C#
var result = users.Where(user => user.Name != null && user.Name.Contains("田"));

null条件演算子を使うと、次のように書けます。

C#
var result = users.Where(user => user.Name?.Contains("田") == true);

また、コレクション自体が null の可能性がある場合も注意が必要です。

C#
List<User>? users = GetUsers();

var result = users.Where(user => user.Age >= 20);

usersnull の場合、上記のコードはエラーになります。

対策として、空のコレクションを使う方法があります。

C#
var result = (users ?? new List<User>())
.Where(user => user.Age >= 20);

または、メソッド側で空のListを返す設計にすると、呼び出し側が扱いやすくなります。

C#
public List<User> GetUsers()
{
return new List<User>();
}

8-3. パフォーマンスを意識すべきケース

LINQは便利ですが、パフォーマンスを意識すべきケースもあります。

特に注意したいのは、何度も同じLINQを実行してしまうケースです。

C#
var result = users.Where(user => user.Age >= 20);

int count = result.Count();
var list = result.ToList();

この場合、CountToList のタイミングで、条件判定が複数回実行される可能性があります。

結果を何度も使う場合は、先に ToList で確定するとよいです。

C#
var result = users
.Where(user => user.Age >= 20)
.ToList();

int count = result.Count;

また、大量データに対してLINQを使う場合は、処理順も重要です。

C#
var result = users
.Where(user => user.IsActive)
.Select(user => new
{
user.Name,
user.Age
})
.ToList();

基本的には、先に Where で件数を減らしてから、SelectOrderBy を行うと効率的です。

データベースに対するLINQでは、ToList の位置にも注意が必要です。早い段階で ToList すると、大量データをメモリに読み込んでから絞り込むことになる場合があります。

C#
var result = dbContext.Users
.ToList()
.Where(user => user.Age >= 20);

このような書き方より、可能であれば次のように条件を先に書く方が自然です。

C#
var result = dbContext.Users
.Where(user => user.Age >= 20)
.ToList();

8-4. LINQを使いすぎると読みにくくなるケース

LINQは便利ですが、すべてをLINQで書けばよいわけではありません。

たとえば、次のように条件や変換が複雑になりすぎると、読みにくくなります。

C#
var result = users
.Where(user => user.Age >= 20 && user.Score >= 80 && user.Department != null && user.Department.Contains("開"))
.OrderByDescending(user => user.Score)
.Select(user => new
{
Name = user.Name.Trim(),
Label = $"{user.Department}:{user.Score}:{(user.Age >= 30 ? "ベテラン" : "若手")}"
})
.ToList();

このような場合は、条件を変数やメソッドに分けると読みやすくなります。

C#
bool IsTargetUser(User user)
{
return user.Age >= 20
&& user.Score >= 80
&& user.Department != null
&& user.Department.Contains("開");
}
C#
var result = users
.Where(IsTargetUser)
.OrderByDescending(user => user.Score)
.Select(user => new
{
Name = user.Name.Trim(),
Label = CreateLabel(user)
})
.ToList();

CreateLabel もメソッドに分けられます。

C#
string CreateLabel(User user)
{
var category = user.Age >= 30 ? "ベテラン" : "若手";
return $"{user.Department}:{user.Score}:{category}";
}

LINQは「短く書くため」だけではなく、「読みやすく書くため」に使うことが大切です。

8-5. デバッグしやすい書き方のコツ

LINQはメソッドチェーンで書けるため便利ですが、長くなりすぎるとデバッグしにくくなります。

デバッグしやすくするには、処理を段階的に分ける方法があります。

C#
var activeUsers = users.Where(user => user.Age >= 20);

var sortedUsers = activeUsers.OrderByDescending(user => user.Score);

var result = sortedUsers.Select(user => new
{
user.Name,
user.Score
});

一時変数に分けることで、各段階の結果を確認しやすくなります。

また、条件式が複雑な場合は、ラムダ式の中に長い処理を書かず、メソッドに分けるのがおすすめです。

C#
var result = users.Where(user => IsHighScoreAdult(user));
C#
bool IsHighScoreAdult(User user)
{
return user.Age >= 20 && user.Score >= 80;
}

メソッド名を適切に付けることで、コードの意図がわかりやすくなります。

LINQのデバッグでは、必要に応じて ToList を使って結果を確定させることもあります。

C#
var filteredUsers = users
.Where(user => user.Age >= 20)
.ToList();

ただし、実際の処理では不要な ToList を増やしすぎないように注意しましょう。

9. LINQ初心者がつまずきやすい疑問

9-1. WhereとSelectの違い

WhereSelect は、LINQの中でも特によく使うメソッドですが、役割が違います。

Where は、条件に合う要素だけを残すメソッドです。

C#
var adults = users.Where(user => user.Age >= 20);

このコードは、20歳以上のユーザーだけを抽出します。

一方、Select は、要素を別の形に変換するメソッドです。

C#
var names = users.Select(user => user.Name);

このコードは、ユーザー一覧から名前だけを取り出します。

違いをまとめると、次のようになります。

メソッド役割
Where条件で絞り込む
Selectデータの形を変える

両方を組み合わせると、条件に合うデータから必要な項目だけを取り出せます。

C#
var names = users
.Where(user => user.Age >= 20)
.Select(user => user.Name);

9-2. FirstとFirstOrDefaultの違い

FirstFirstOrDefault は、どちらも最初の1件を取得するメソッドです。

違いは、データが見つからなかった場合の動作です。

C#
var user = users.First(user => user.Id == 1);

First は、条件に合うデータが見つからないと例外を発生させます。

C#
var user = users.First(user => user.Id == 999);

一方、FirstOrDefault は、見つからなかった場合に既定値を返します。

C#
var user = users.FirstOrDefault(user => user.Id == 999);

if (user == null)
{
Console.WriteLine("ユーザーが見つかりませんでした");
}

使い分けは次のとおりです。

メソッド使う場面
First必ずデータが存在するとわかっている場合
FirstOrDefaultデータがない可能性がある場合

実務では、検索結果が存在しない可能性を考えて、FirstOrDefault を使うことが多いです。

9-3. IEnumerableとListの違い

IEnumerableList の違いも、LINQ初心者がつまずきやすいポイントです。

IEnumerable は、順番に列挙できるデータを表すインターフェースです。

C#
IEnumerable<User> result = users.Where(user => user.Age >= 20);

List は、要素を追加、削除、インデックスアクセスできる具体的なコレクションです。

C#
List<User> result = users
.Where(user => user.Age >= 20)
.ToList();

違いをまとめると、次のようになります。

特徴
IEnumerable順番に取り出せる。LINQの結果でよく使われる
List追加・削除・件数取得・インデックスアクセスができる

LINQの WhereSelect の戻り値は、多くの場合 IEnumerable です。

Listとして扱いたい場合は、ToList を使います。

C#
var list = users
.Where(user => user.Age >= 20)
.ToList();

9-4. ToListはいつ使うべきか

ToList は、LINQの結果をListとして確定したいときに使います。

たとえば、次のような場合です。

C#
var result = users
.Where(user => user.Age >= 20)
.ToList();

ToList を使うべき場面は、主に次のとおりです。

場面理由
結果を何度も使う毎回LINQが再実行されるのを防ぐ
結果をListとして返したい戻り値の型をListにできる
その時点の結果を固定したい遅延実行の影響を避けられる
要素を追加・削除したいListの機能を使える

一方で、すぐにforeachで1回だけ使う場合は、必ずしも ToList は必要ありません。

C#
foreach (var user in users.Where(user => user.Age >= 20))
{
Console.WriteLine(user.Name);
}

不要な ToList はメモリ使用量を増やす原因になることがあります。

よくない例です。

C#
var result = users
.Where(user => user.Age >= 20)
.ToList()
.Select(user => user.Name)
.ToList();

最後にまとめてList化すれば十分です。

C#
var result = users
.Where(user => user.Age >= 20)
.Select(user => user.Name)
.ToList();

9-5. LINQはSQLの知識がなくても使えるか

LINQはSQLに似た考え方を持っていますが、SQLの知識がなくても使えます。

特に、配列やListに対して使うLINQであれば、C#の基本文法とラムダ式を理解していれば十分です。

たとえば、次のコードはSQLを知らなくても意味がわかりやすいはずです。

C#
var result = users.Where(user => user.Age >= 20);

これは、20歳以上のユーザーを取り出す処理です。

名前だけを取り出す場合は、次のように書きます。

C#
var names = users.Select(user => user.Name);

年齢順に並べる場合は、次のように書きます。

C#
var sortedUsers = users.OrderBy(user => user.Age);

SQLの知識があると、データベースに対するLINQを理解しやすくなる場面はあります。しかし、C# LINQの基本を学ぶうえでは、まず WhereSelectOrderBy の3つを押さえることが大切です。

まとめ

C# LINQは、配列やList、オブジェクトの一覧を効率よく操作するための便利な機能です。条件に合うデータを抽出したり、必要な項目だけ取り出したり、並び替えや集計を行ったりできます。

特に重要なのは、次の3つです。

メソッド役割
Where条件に合うデータを抽出する
Select必要なデータだけを取り出す、または変換する
OrderByデータを昇順に並び替える

基本的な使い方は次のようになります。

C#
var result = users
.Where(user => user.Age >= 20)
.OrderBy(user => user.Age)
.Select(user => new
{
user.Name,
user.Age
})
.ToList();

このコードでは、20歳以上のユーザーを抽出し、年齢順に並べ、名前と年齢だけを取り出しています。

LINQを使うと、foreachで何行も書いていた処理を短くわかりやすく書けます。ただし、遅延実行、null参照、不要な ToList、複雑すぎるメソッドチェーンには注意が必要です。

C# LINQを学び始めたら、まずは WhereSelectOrderBy を使えるようになることを目指しましょう。その後、FirstOrDefaultAnyCountGroupByDistinctTakeSkip などを覚えていくと、実務で扱えるデータ操作の幅が大きく広がります。