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の基本から、よく使う Where、Select、OrderBy、さらに First、Any、GroupBy、ToList などの便利なメソッドまで、初心者にもわかりやすく解説します。
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は、主にデータベースに対して問い合わせを行う言語です。
SQLSELECT * FROM Users WHERE Age >= 20;
LINQでは、C#のコード内で似たような考え方を使えます。
C#var adults = users.Where(user => user.Age >= 20);
違いを整理すると、次のようになります。
| 種類 | 主な用途 |
|---|---|
| foreach | 1件ずつ順番に処理する |
| 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;
どちらも同じ意味です。
メソッド構文は、Where、Select、OrderBy などのメソッドをつなげて書きます。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);
この場合、user は users の中にある1件のユーザーを表しています。
ラムダ式の変数名は自由に決められます。
C#var adults = users.Where(x => x.Age >= 20);
ただし、x よりも user のように意味のある名前を使った方が、読みやすいコードになります。
2-3. IEnumerableとIQueryableの違い
LINQを学ぶと、IEnumerable と IQueryable という言葉が出てきます。
初心者のうちは難しく感じるかもしれませんが、まずは次のように理解するとよいでしょう。
| 型 | 主な用途 |
|---|---|
| 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 も結果に含まれます。
一方、ToList や ToArray を使うと、その時点で処理が実行されます。これを 即時実行 といいます。
C#var result = numbers.Where(n => n >= 3).ToList();
ToList を使うと、その時点の結果がListとして確定します。
主な即時実行のメソッドには、次のようなものがあります。
| メソッド | 内容 |
|---|---|
| ToList | Listに変換する |
| 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. 文字列条件で絞り込む方法
文字列を条件にする場合は、==、Contains、StartsWith、EndsWith などを使います。
部署が「開発」のユーザーだけを取得する例です。
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
});
この結果は、Name と Department だけを持つデータの一覧になります。
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を組み合わせる方法
Where と Select は、LINQで特によく組み合わせて使います。
たとえば、20歳以上のユーザーの名前だけを取得する場合は、次のように書きます。
C#var names = users
.Where(user => user.Age >= 20)
.Select(user => user.Name);
処理の流れは次のとおりです。
Whereで20歳以上のユーザーを抽出するSelectで名前だけを取り出す
開発部門のユーザーを表示用データに変換する例です。
C#var result = users
.Where(user => user.Department == "開発")
.Select(user => new
{
user.Name,
user.Score
});
Where と Select の順番も重要です。
一般的には、先に 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());
Name が null の場合、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 を返します。
使い分けは次のとおりです。
| メソッド | 意味 |
|---|---|
| Any | 1件でも条件を満たすか |
| 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件を飛ばして、それ以降のユーザーを取得します。
Take と Skip は、ページング処理でよく使います。
たとえば、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);
一覧画面や検索結果のページングでは、Skip と Take の組み合わせがよく使われます。
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の Where や Select は遅延実行されるため、結果をその時点で確定したい場合に ToList や ToArray を使います。
たとえば、次のコードでは 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
});
処理の流れは次のとおりです。
Whereで販売中の商品だけを抽出するOrderByDescendingで価格が高い順に並び替える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の Where や Select は、多くの場合、遅延実行されます。つまり、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参照エラーにも注意が必要です。
たとえば、次のコードは Name が null の場合にエラーになります。
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);
users が null の場合、上記のコードはエラーになります。
対策として、空のコレクションを使う方法があります。
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();
この場合、Count と ToList のタイミングで、条件判定が複数回実行される可能性があります。
結果を何度も使う場合は、先に 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 で件数を減らしてから、Select や OrderBy を行うと効率的です。
データベースに対する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の違い
Where と Select は、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の違い
First と FirstOrDefault は、どちらも最初の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の違い
IEnumerable と List の違いも、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の Where や Select の戻り値は、多くの場合 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の基本を学ぶうえでは、まず Where、Select、OrderBy の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を学び始めたら、まずは Where、Select、OrderBy を使えるようになることを目指しましょう。その後、FirstOrDefault、Any、Count、GroupBy、Distinct、Take、Skip などを覚えていくと、実務で扱えるデータ操作の幅が大きく広がります。

