LINQ拡張メソッドまとめ

2025年1月15日水曜日

C#

記事のカテゴリー: C#、.NET 9

LINQ拡張メソッド(System.Linq名前空間のEnumerableクラスに宣言された拡張メソッド、静的メソッド)について、概要と使用例をまとめています。

シーケンスの生成

DefaultIfEmptyEmpty(静的メソッド)Range(静的メソッド)Repeat(静的メソッド)

部分シーケンスの生成

SkipSkipLastSkipWhileTakeTakeLastTakeWhileWhere

シーケンスの変換

AsEnumerableCastIndexOfTypeToArrayToDictionaryToHashSetToListToLookupZip

操作

ChunkConcatGroupByGroupJoinJoinSelectSelectManyTryGetNonEnumeratedCount

要素の操作

AppendElementAtElementAtOrDefaultFirstFirstOrDefaultLastLastOrDefaultPrependSingleSingleOrDefault

判断

AllAnyContainsSequenceEqual

集計

AggregateAverageCountLongCountMaxMaxByMinMinBySum

集合演算

DistinctDistinctByExceptExceptByIntersectIntersectByUnionUnionBy

並べ替え

OrderOrderByOrderByDescendingOrderDescendingReverseThenByThenByDescending

Aggregate

すべての要素で集計関数を実行して集計値を生成します。初期値を指定することや、集計値とシーケンスの要素を異なる型にすることができます。

int[] seq = [1, 2, 3, 4, 5];
int value = seq.Aggregate((sum, element) => sum + element);
// 15 (合計)

string[] seq = ["One", "Two", "Three", "Four", "Five"];
int value = seq.Aggregate(10, (sum, element) => sum + element.Length);
// 29 (文字数の合計 + 初期値 10)

All

すべての要素が条件を満たすかどうかを判断します。falseを返す要素が見つかるとその時点で処理は終わります。

int[] seq = [2, 4, 6, 8, 10];
bool value = seq.All(element => element % 2 == 0);
// true (すべての要素が偶数)

Any

条件を満たす要素があるかどうかを判断します。trueを返す要素が見つかるとその時点で処理は終わります。条件がない場合は、シーケンスが要素を持っていればtrue、空ならfalseを返します。

int[] seq = [1, 2, 3, 4, 5];
bool value = seq.Any(element => element % 2 == 0);
// true (偶数の要素を含む)

int[] seq = [1, 2, 3, 4, 5];
bool value = seq.Any();
// true (要素を持っている)

Append

指定した値を最後に追加します。

int[] seq = [1, 2, 3, 4, 5];
IEnumerable<int> value = seq.Append(6);
// [1, 2, 3, 4, 5, 6]

AsEnumerable

IEnumerable<T>に変換します。派生クラスからLinq拡張メソッドを呼び出すために使います。

Average

平均値を返します。要素の型がnull許容型の場合、値がnullの要素は無視して、シーケンスが空かすべての要素の値がnullのときはnullを返します。それぞれの要素から生成した結果の平均値を返すこともできます。

int[] seq = [1, 2, 3, 4, 5];
double value = seq.Average();
// 3

int[] seq = [];
double value = seq.Average();
// InvalidOperationException がスローされる

int?[] seq = [1, 2, 3, 4, null];
double? value = seq.Average();
// 2.5 (null を除いた平均値)

string[] seq = ["One", "Two", "Three", "Four", "Five"];
double value = seq.Average(element => element.Length);
// 3.8 (文字数の平均値)

Cast

指定した型のシーケンスに変換します。関連するメソッド: OfType

object[] seq = [1, 2, 3, 4, 5];
IEnumerable<int> value = seq.Cast<int>();
// object 型の配列を int 型のシーケンスに変換

object[] seq = [1, 2, "3", 4, 5];
int[] value = seq.Cast<int>().ToArray();
// (Cast は遅延評価のため ToArray で) InvalidCastException がスローされる

Chunk

シーケンスを指定した長さの配列に分けます

int[] seq = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
IEnumerable<int[]> value = seq.Chunk(3);
// [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]

Concat

2つのシーケンスを結合します。

int[] x = [1, 2, 3];
int[] y = [4, 5, 6];
IEnumerable<int> value = x.Concat(y);
 // [1, 2, 3, 4, 5, 6]

Contains

指定した値と一致する要素を持っているかどうかを判断します。要素の比較をカスタマイズする(IEqualityComparer<T>を実装したクラスを使う)こともできます。

int[] seq = [1, 2, 3, 4, 5];
bool value = seq.Contains(3);
// true

int[] seq = [1, 2, 3, 4, 5];
bool value = seq.Contains(3, EqualityComparer);
// IEqualityComparer<T> を実装したクラスで比較する

Count

要素の数を返します。条件を指定した場合は条件を満たす要素の数を返します。関連するメソッド: LongCountTryGetNonEnumeratedCount

int[] seq = [1, 2, 3, 4, 5];
int value = seq.Count();
// 5

int[] seq = [1, 2, 3, 4, 5];
int value = seq.Count(element => element % 2 == 0);
// 2 (偶数の要素の数)

DefaultIfEmpty

シーケンスが空なら既定値(default(T))を唯一の要素として持つシーケンスを生成します。既定値を指定することもできます。

int[] seq = [];
IEnumerable<int> value = seq.DefaultIfEmpty();
// [0] (default(int))
     
int[] seq = [1, 2, 3, 4, 5];
IEnumerable<int> value = seq.DefaultIfEmpty();
// [1, 2, 3, 4, 5]

int[] seq = [];
IEnumerable<int> value = seq.DefaultIfEmpty(3);
// [3] (指定した既定値)

Distinct

重複する要素を削除します。要素の比較をカスタマイズする(IEqualityComparer<T>を実装したクラスを使う)こともできます。

int[] seq = [1, 2, 3, 1, 2, 3];
IEnumerable<int> value = seq.Distinct();
// [1, 2, 3]

int[] seq = [1, 2, 3, 1, 2, 3];
IEnumerable<int> value = seq.Distinct(EqualityComparer);
// IEqualityComparer<T> を実装したクラスで比較する

DistinctBy

指定したキーを比較して重複する要素を削除します。キーの比較をカスタマイズする(IEqualityComparer<T>を実装したクラスを使う)こともできます。

// 従業員クラス
class Employee
{
    public int ID { get; set; }
    public string Dept { get; set; }
    public string Name { get; set; }
}
...
List<Employee> employees = [
    new() { ID = 1, Dept = "総務部", Name = "佐藤太郎" },
    new() { ID = 2, Dept = "総務部", Name = "鈴木花子" },
    new() { ID = 3, Dept = "総務部", Name = "高橋太郎" },
    new() { ID = 4, Dept = "人事部", Name = "田中花子" },
    new() { ID = 5, Dept = "人事部", Name = "伊藤太郎" }
];
IEnumerable<Employee> value = employees.OrderBy(employee=> employee.ID)
    .DistinctBy(employee => employee.Dept);
// [
//     { ID = 1, Dept = "総務部", Name = "佐藤太郎" },
//     { ID = 4, Dept = "人事部", Name = "田中花子" }
// ]
// (部署ごとに ID が一番小さい従業員)

IEnumerable<Employee> value = employees.OrderBy(employee=> employee.ID)
    .DistinctBy(employee => employee.Dept, EqualityComparer);
// IEqualityComparer<T> を実装したクラスで比較する

ElementAt

指定したインデックスの要素を返します

int[] seq = [1, 2, 3, 4, 5];
int value = seq.ElementAt(2);
// 3

int[] seq = [1, 2, 3, 4, 5];
int value = seq.ElementAt(10);
// ArgumentOutOfRangeException がスローされる

ElementAtOrDefault

指定したインデックスの要素か既定値(default(T))を返します

int[] seq = [1, 2, 3, 4, 5];    
int value = seq.ElementAtOrDefault(10);
// 0 (default(int))

Empty(静的メソッド)

空のシーケンスを生成します。

IEnumerable<int> value = Enumerable.Empty<int>();
// []

Except

2つのシーケンスの差集合※を返します。要素の比較をカスタマイズする(IEqualityComparer<T>を実装したクラスを使う)こともできます。

※2つのシーケンスX、Yにおいて、シーケンスXからシーケンスYに含まれる要素と重複する要素を削除した内容になります。

int[] x = [1, 2, 3, 4, 5];
int[] y = [2, 4, 6];
IEnumerable<int> value = x.Except(y);
// [1, 3, 5]

int[] x = [1, 2, 3, 1, 2, 3];
int[] y = [2, 4, 6];
IEnumerable<int> value = x.Except(y);
// [1, 3]

int[] x = [1, 2, 3, 4, 5];
int[] y = [2, 4, 6];
IEnumerable<int> value = x.Except(y, EqualityComparer);
// IEqualityComparer<T> を実装したクラスで比較する

ExceptBy

指定したキーを比較して2つのシーケンスの差集合を返します。キーの比較をカスタマイズする(IEqualityComparer<T>を実装したクラスを使う)こともできます。

// 顧客クラス
class Customer
{
    public int ID { get; set; }
    public string Name { get; set; }
}
// 購入履歴クラス
class PurchaseHistoryItem
{
    public int CustomerID { get; set; }
    public int Price { get; set; }
}
...
Customer[] customers = [
    new() { ID = 1, Name = "佐藤太郎" },
    new() { ID = 2, Name = "鈴木花子" },
    new() { ID = 3, Name = "高橋太郎" },
    new() { ID = 4, Name = "田中花子" },
    new() { ID = 5, Name = "伊藤太郎" }
];
PurchaseHistoryItem[] history = [
    new() { CustomerID = 1, Price = 1000 },
    new() { CustomerID = 2, Price = 2000 },
    new() { CustomerID = 3, Price = 3000 },
    new() { CustomerID = 1, Price = 4000 },
    new() { CustomerID = 2, Price = 5000 }
];

IEnumerable<Customer> value = customers.ExceptBy(
    history.Select(item => item.CustomerID), customer => customer.ID);
// [
//     { ID = 4, Name = "田中花子" },
//     { ID = 5, Name = "伊藤太郎" }
// ]
// (購入履歴がない顧客)

IEnumerable<Customer> value = customers.ExceptBy(
    history.Select(item => item.CustomerID), customer => customer.ID, EqualityComparer);
// IEqualityComparer<T> を実装したクラスで比較する

First

最初の要素を返します。条件を指定した場合は条件を満たす最初の要素を返します。

int[] seq = [1, 2, 3, 4, 5];
int value = seq.First();
// 1

int[] seq = [];
int value = seq.First();
// InvalidOperationException がスローされる

int[] seq = [1, 2, 3, 4, 5];
int value = seq.First(element => element % 2 == 0);
// 2 (最初の偶数の要素)

FirstOrDefault

最初の要素か既定値 (default(T)) を返します。条件を指定した場合は条件を満たす最初の要素か既定値を返します。既定値を指定することもできます。

int[] seq = [];
int value = seq.FirstOrDefault();
// 0 (default(int))

int[] seq = [1, 3, 5, 7, 9];
int value = seq.FirstOrDefault(element => element % 2 == 0, -1);
// -1 (指定した既定値)

GroupBy

2つの機能があります。

  1. 指定したキーでグループ化して、それらのグループのシーケンスを生成します。
  2. 指定したキーでグループ化して、すべてのグループで指定した関数を実行して、結果のシーケンスを生成します。

キーの比較をカスタマイズする(IEqualityComparer<T>を実装したクラスを使う)こともできます。

// 機能 1
// 従業員クラス
class Employee {
    public string Dept { get; set; }
    public string Name { get; set; }
}
...
List<Employee> employees = [
    new() { Dept = "総務部", Name = "佐藤太郎" },
    new() { Dept = "総務部", Name = "鈴木花子" },
    new() { Dept = "総務部", Name = "高橋太郎" },
    new() { Dept = "人事部", Name = "田中花子" },
    new() { Dept = "人事部", Name = "伊藤太郎" }
];
IEnumerable<IGrouping<string, Employee>> value = employees.GroupBy(
    employee => employee.Dept);
// [
//     {
//         Key = "総務部",
//         [
//             { Dept = "総務部", Name = "佐藤太郎" },
//             { Dept = "総務部", Name = "鈴木花子" },
//             { Dept = "総務部", Name = "高橋太郎" }
//         ]
//     },
//     {
//         Key = "人事部",
//         [
//             { Dept = "人事部", Name = "田中花子" },
//             { Dept = "人事部", Name = "伊藤太郎" }
//         ]
//     }
// ]
// (部署ごとにグループ化)

IEnumerable<IGrouping<string, string>> value = employees.GroupBy(
    employee => employee.Dept, employee => employee.Name);
// [
//      {
//           Key = "総務部",
//           ["佐藤太郎", "鈴木花子", "高橋太郎"]
//      },
//      {
//           Key = "人事部",
//           ["田中花子", "伊藤太郎"]
//      }
// ]

IEnumerable<IGrouping<string, Employee>> value = employees.GroupBy(
    employee => employee.Dept, EqualityComparer);
// IEqualityComparer<T> を実装したクラスで比較する

//機能 2
IEnumerable<string> value = employees.GroupBy(
    employee => employee.Dept,
    (dept, employees) => $"{dept} {employees.Count()}人");
// ["総務部 3人", "人事部 2人"]

IEnumerable<string> value = employees.GroupBy(
    employee => employee.Dept,
    employee => employee.Name,
    (dept, names) => $"{dept} {string.Join(',', names)}");
// ["総務部 佐藤太郎,鈴木花子,高橋太郎", "人事部 田中花子,伊藤太郎"]

IEnumerable<string> value = employees.GroupBy(
    employee => employee.Dept,
    (dept, employees) => $"{dept} {employees.Count()}人",
    EqualityComparer);
// IEqualityComparer<T> を実装したクラスで比較する

GroupJoin

2つのシーケンスから指定したキーが一致する組み合わせ(1対多)を抽出して、すべての組み合わせで指定した関数を実行して、結果のシーケンスを生成します。キーの比較をカスタマイズする(IEqualityComparer<T>を実装したクラスを使う)こともできます。

// 顧客クラス
class Customer {
    public int ID { get; set; }
    public string Name { get; set; }
}
// 購入履歴クラス
class PurchaseHistoryItem {
    public int CustomerID { get; set; }
    public int Price { get; set; }
}
...
Customer[] customers = [
    new() { ID = 1, Name = "佐藤太郎" }, 
    new() { ID = 2, Name = "鈴木花子" }
];
PurchaseHistoryItem[] history = [
    new() { CustomerID = 1, Price = 1000 },
    new() { CustomerID = 1, Price = 2000 },
    new() { CustomerID = 2, Price = 3000 },
    new() { CustomerID = 2, Price = 4000 },
    new() { CustomerID = 2, Price = 5000 }
];

IEnumerable<string> value = customers.GroupJoin(
    history, 
    customer => customer.ID,
    item => item.CustomerID,
    (customer, items) => $"{customer.Name} {items.Average((item) => item.Price)}円");
// ["佐藤太郎 1500円", "鈴木花子 4000円"] (顧客の平均購入金額)

IEnumerable<string> value = customers.GroupJoin(
    history, 
    customer => customer.ID,
    item => item.CustomerID,
    (customer, items) => $"{customer.Name} {items.Average((item) => item.Price)}円",
    EqualityComparer);
// IEqualityComparer<T> を実装したクラスで比較する

Index

要素とインデックスのタプルのシーケンスを生成します。

string[] seq = ["One", "Two", "Three", "Four", "Five"];
var value = seq.Index();
// [
//     (Index: 0, Item: "One"),
//     (Index: 1, Item: "Two"),
//     (Index: 2, Item: "Three"),
//     (Index: 3, Item: "Four"),
//     (Index: 4, Item: "Five")
// ]

Intersect

2つのシーケンスの積集合※を返します。要素の比較をカスタマイズする(IEqualityComparer<T>を実装したクラスを使う)こともできます。

※2つのシーケンスX、Yにおいて、シーケンスXからシーケンスYに含まれない要素と重複する要素を削除した内容になります。

int[] x = [1, 2, 3, 4, 5];
int[] y = [2, 4, 6];
IEnumerable<int> value = x.Intersect(y);
// [2, 4]

int[] x = [1, 2, 3, 1, 2, 3];
int[] y = [2, 4, 6];
IEnumerable<int> value = x.Intersect(y);
// [2]

int[] x = [1, 2, 3, 4, 5];
int[] y = [2, 4, 6];
IEnumerable<int> value = x.Intersect(y, EqualityComparer);
// IEqualityComparer<T> を実装したクラスで比較する

IntersectBy

指定したキーを比較して2つのシーケンスの積集合を返します。キーの比較をカスタマイズする(IEqualityComparer<T>を実装したクラスを使う)こともできます。

// 顧客クラス
class Customer
{
    public int ID { get; set; }
    public string Name { get; set; }
}
// 購入履歴クラス
class PurchaseHistoryItem
{
    public int CustomerID { get; set; }
    public int Price { get; set; }
}
...
Customer[] customers = [
    new() { ID = 1, Name = "佐藤太郎" },
    new() { ID = 2, Name = "鈴木花子" },
    new() { ID = 3, Name = "高橋太郎" },
    new() { ID = 4, Name = "田中花子" },
    new() { ID = 5, Name = "伊藤太郎" }
];
PurchaseHistoryItem[] history = [
    new() { CustomerID = 1, Price = 1000 },
    new() { CustomerID = 2, Price = 2000 },
    new() { CustomerID = 3, Price = 3000 },
    new() { CustomerID = 1, Price = 4000 },
    new() { CustomerID = 2, Price = 5000 }
];

IEnumerable<Customer> value = customers.IntersectBy(
    history.Select(item => item.CustomerID), customer => customer.ID);
// [
//     { ID = 1, Name = "佐藤太郎" },
//     { ID = 2, Name = "鈴木花子" },
//     { ID = 3, Name = "高橋太郎" }
// ]
// (購入履歴がある顧客)

IEnumerable<Customer> value = customers.IntersectBy(
    history.Select(item => item.CustomerID), customer => customer.ID, EqualityComparer);
// IEqualityComparer<T> を実装したクラスで比較する

Join

2つのシーケンスから指定したキーが一致する組み合わせを抽出して、すべての組み合わせで指定した関数を実行して、結果のシーケンスを生成します。キーの比較をカスタマイズする(IEqualityComparer<T>を実装したクラスを使う)こともできます。

// 部署クラス
class Department {
    public int ID { get; set; }
    public string Name { get; set; }
}
// 従業員クラス
class Employee {
    public int DeptID { get; set; }
    public string Name { get; set; }
}
...
List<Department> depts = [
    new() { ID = 1, Name = "総務部" },
    new() { ID = 2, Name = "人事部" }
];
List<Employee> employees = [
    new() { DeptID = 1, Name = "佐藤太郎" },
    new() { DeptID = 2, Name = "鈴木花子" },
    new() { DeptID = 1, Name = "高橋太郎" },
    new() { DeptID = 2, Name = "田中花子" },
    new() { DeptID = 1, Name = "伊藤太郎" }
];
IEnumerable<string> value = depts.Join(
    employees,
    dept => dept.ID,
    employee => employee.DeptID,
    (dept, employee) => $"{dept.Name} {employee.Name}");
// ["総務部 佐藤太郎", "総務部 高橋太郎", "総務部 伊藤太郎", "人事部 鈴木花子", "人事部 田中花子"]

IEnumerable<string> value = depts.Join(
    employees,
    dept => dept.ID,
    employee => employee.DeptID,
    (dept, employee) => $"{dept.Name} {employee.Name}",
    EqualityComparer);
// IEqualityComparer<T> を実装したクラスで比較する

Last

最後の要素を返します。条件を指定した場合は条件を満たす最後の要素を返します。

int[] seq = [1, 2, 3, 4, 5];
int value = seq.Last();
// 5

int[] seq = [];
int value = seq.Last();
// InvalidOperationException がスローされる

int[] seq = [1, 2, 3, 4, 5];
int value = seq.Last(element => element % 2 == 0);
// 4 (最後の偶数の要素)

LastOrDefault

最後の要素か既定値(default(T))を返します。条件を指定した場合は条件を満たす最後の要素か既定値を返します。既定値を指定することもできます。

int[] seq = [];
int value = seq.LastOrDefault();
// 0 (default(int))

int[] seq = [1, 3, 5, 7, 9];
int value = seq.LastOrDefault(element => element % 2 == 0, -1);
// -1 (指定した既定値)

LongCount

要素の数をlong型で返します。条件を指定した場合は条件を満たす要素の数を返します。関連メソッド: CountTryGetNonEnumeratedCount

int[] seq = [1, 2, 3, 4, 5];
long value = seq.LongCount();
// 5

int[] seq = [1, 2, 3, 4, 5];
long value = seq.LongCount(element => element % 2 == 0);
// 2 (偶数の要素の数)

Max

最大値を返します。 要素の型がnull許容型の場合、値がnullの要素を無視して、シーケンスが空かすべての要素がnullのときはnullを返します。それぞれの要素から生成した結果の最大値を返すこともできます。

int[] seq = [1, 2, 3, 4, 5];
int value = seq.Max();
// 5

int[] seq = [];
int value = seq.Max();
// InvalidOperationException がスローされる

int?[] seq = [1, 2, 3, 4, null];
int? value = seq.Max();
// 4 (null を除いた最大値)

string[] seq = ["One", "Two", "Three", "Four", "Five"];
int value = seq.Max(element => element.Length);
// 5 (文字数の最大値)

MaxBy

指定したキーを比較して最大値を返します。キーの比較をカスタマイズする(IComparer<T>を実装したクラスを使う)こともできます。

// 従業員クラス
class Employee {
    public int ID { get; set; }
    public string Name { get; set; }
}
...
List<Employee> employees = [
    new() { ID = 1, Name = "佐藤太郎" },
    new() { ID = 2, Name = "鈴木花子" },
    new() { ID = 3, Name = "高橋太郎" },
    new() { ID = 4, Name = "田中花子" },
    new() { ID = 5, Name = "伊藤太郎" }
];
Employee? value = employees.MaxBy(employee => employee.ID);
// { ID = 5, Name = "伊藤太郎" } (ID が一番大きい従業員)

Employee? value = employees.MaxBy(employee => employee.ID, Comparer);
// IComparer<T> を実装したクラスで比較する

Min

最小値を返します。要素の型がnull許容型の場合、値がnullの要素を無視して、シーケンスが空かすべての要素がnullのときはnullを返します。それぞれの要素から生成した結果の最小値を返すこともできます。

int[] seq = [1, 2, 3, 4, 5];
int value = seq.Min();
// 1

int[] seq = [];
int value = seq.Min();
// InvalidOperationException がスローされる

int?[] seq = [1, 2, 3, 4, null];
int? value = seq.Min();
// 1 (null を除いた最小値)

string[] seq = ["One", "Two", "Three", "Four", "Five"];
int value = seq.Min(element => element.Length);
// 3 (文字数の最小値)

MinBy

指定したキーを比較して最小値を返します。キーの比較をカスタマイズする(IComparer<T>を実装したクラスを使う)こともできます。

// 従業員クラス
class Employee {
    public int ID { get; set; }
    public string Name { get; set; }
}
...
List<Employee> employees = [
    new() { ID = 1, Name = "佐藤太郎" },
    new() { ID = 2, Name = "鈴木花子" },
    new() { ID = 3, Name = "高橋太郎" },
    new() { ID = 4, Name = "田中花子" },
    new() { ID = 5, Name = "伊藤太郎" }
];
Employee? value = employees.MinBy(employee => employee.ID);
// { ID = 1, Name = "佐藤太郎" } (ID が一番小さい従業員)

Employee? value = employees.MinBy(employee => employee.ID, Comparer);
// IComparer<T> を実装したクラスで比較する

OfType

指定した型のシーケンスに変換します。変換できない要素は削除します。 関連メソッド: Cast

object[] seq = [1, 2, 3, 4, 5];
IEnumerable<int> value = seq.OfType<int>();
// object 型の配列を int 型のシーケンスに変換

object[] seq = [1, 2, "3", 4, 5];
IEnumerable<int> value = seq.OfType<int>();
// [1, 2, 4, 5]

Order

要素を昇順に並べ替えます。要素の比較をカスタマイズする(IComparer<T>を実装したクラスを使う)こともできます。

int[] seq = [1, -2, 3, -4, 5];
IEnumerable<int> value = seq.Order();
// [-4, -2, 1, 3, 5]

int[] seq = [1, -2, 3, -4, 5];
IEnumerable<int> value = seq.Order(Comparer);
// IComparer<T> を実装したクラスで比較する

OrderBy

指定したキーを比較して要素を昇順に並べ替えます。キーの比較をカスタマイズする(IComparer<T>を実装したクラスを使う)こともできます。

// 従業員クラス
class Employee {
    public int ID { get; set; }
    public string Name { get; set; }
}
...
List<Employee> employees = [
    new() { ID = 1, Name = "佐藤太郎" },
    new() { ID = 12, Name = "鈴木花子" },
    new() { ID = 3, Name = "高橋太郎" },
    new() { ID = 14, Name = "田中花子" },
    new() { ID = 5, Name = "伊藤太郎" }
];
IEnumerable<Employee> value = employees.OrderBy(employee => employee.ID);
// [
//     { ID = 1, Name = "佐藤太郎" },
//     { ID = 3, Name = "高橋太郎" },
//     { ID = 5, Name = "伊藤太郎" },
//     { ID = 12, Name = "鈴木花子" },
//     { ID = 14, Name = "田中花子" }
// ]

IEnumerable<Employee> value = employees.OrderBy(employee => employee.ID, Comparer);
// IComparer<T> を実装したクラスで比較する

OrderByDescending

指定したキーを比較して要素を降順に並べ替えます。キーの比較をカスタマイズする(IComparer<T>を実装したクラスを使う)こともできます。

// 従業員クラス
class Employee {
    public int ID { get; set; }
    public string Name { get; set; }
}
...
List<Employee> employees = [
    new() { ID = 1, Name = "佐藤太郎" },
    new() { ID = 12, Name = "鈴木花子" },
    new() { ID = 3, Name = "高橋太郎" },
    new() { ID = 14, Name = "田中花子" },
    new() { ID = 5, Name = "伊藤太郎" }
];
IEnumerable<Employee> value = employees.OrderByDescending(employee => employee.ID);
// {
//     { ID = 14, Name = "田中花子" },
//     { ID = 12, Name = "鈴木花子" },
//     { ID = 5, Name = "伊藤太郎" },
//     { ID = 3, Name = "高橋太郎" },
//     { ID = 1, Name = "佐藤太郎" }
// }

IEnumerable<Employee> value = employees.OrderByDescending(employee => employee.ID, Comparer);
// IComparer<T> を実装したクラスで比較する

OrderDescending

要素を降順に並べ替えます。要素の比較をカスタマイズする(IComparer<T>を実装したクラスを使う)こともできます。

int[] seq = [1, -2, 3, -4, 5];
IEnumerable<int> value = seq.OrderDescending();
// { 5, 3, 1, -2, -4 }

int[] seq = [1, -2, 3, -4, 5];
IEnumerable<int> value = seq.OrderDescending(Comparer);
// IComparer<T> を実装したクラスで比較する

Prepend

指定した値を先頭に追加します。

int[] seq = [1, 2, 3, 4, 5];
IEnumerable<int> value = seq.Prepend(0);
// [0, 1, 2, 3, 4, 5]

Range(静的メソッド)

整数のシーケンスを生成します。最初の値と数を指定します。

IEnumerable<int> value = Enumerable.Range(1, 5);
// [1, 2, 3, 4, 5]

Repeat(静的メソッド)

指定した値の繰り返しのシーケンスを生成します。値と繰り返しの回数を指定します。

IEnumerable<int> value = Enumerable.Repeat(1, 5);
// [1, 1, 1, 1, 1]

Reverse

シーケンスの順序を逆転します。

int[] seq = [1, 2, 3, 4, 5];
IEnumerable<int> value = seq.Reverse();
// [5, 4, 3, 2, 1]

Select

すべての要素で指定した関数を実行して結果のシーケンスを生成します。

string[] seq = ["One", "Two", "Three", "Four", "Five"];
IEnumerable<int> value = seq.Select(element => element.Length);
// [3, 3, 5, 4, 4] (文字数のシーケンス)

string[] seq = ["One", "Two", "Three", "Four", "Five"];
var value = seq.Select((element, index) => (Index: index, Item: element.Length))
    .Where(element => element.Index % 2 == 0);
// [
//     (Index: 0, Item: 3),
//     (Index: 2, Item: 5),
//     (Index: 4, Item: 4)
// ]
// (インデックスが偶数のみ)

SelectMany

2つの機能があります。

  1. すべての要素で指定した関数を実行してシーケンスを生成して、それらのシーケンスを結合したシーケンスを返します
  2. すべての要素で指定した関数1を実行してシーケンスを生成して、すべてのシーケンスのすべての要素で指定した関数2を実行して、結果のシーケンスを生成します。
// 機能1
// フォルダークラス
class Folder {
    public string Name { get; set; }
    public File[] Files { get; set; }
}
// ファイルクラス
class File {
    public string Name { get; set; }
}
...
Folder[] folders = [
    new() {
        Name = "プロジェクト1",
        Files = [new() { Name = "スケジュール1" }, new() { Name = "議事録1" }]
    },
    new() {
        Name = "プロジェクト2",
        Files = [new() { Name = "スケジュール2" }, new() { Name = "議事録2" }]
    },
    new() {
        Name = "プロジェクト3",
        Files = [new() { Name = "スケジュール3" }, new() { Name = "議事録3" }]
    }
];
IEnumerable<File> value = folders.SelectMany(folder => folder.Files);
// [
//     { Name: "スケジュール1" },
//     { Name: "議事録1" },
//     { Name: "スケジュール2" },
//     { Name: "議事録2" },
//     ...
// ]
// (すべてのフォルダーのファイル)

IEnumerable<File> value = folders.SelectMany(
    (folder, index) => (index % 2 == 0) ? folder.Files : []);
// [
//     { Name: "スケジュール1" },
//     { Name: "議事録1" },
//     { Name: "スケジュール3" },
//     { Name: "議事録3" }
// ]
// (インデックスが偶数のフォルダーのみ)

// 機能2
IEnumerable<string> value = folders.SelectMany(
    folder => folder.Files,
    (folder, file) => $"{folder.Name} {file.Name}");
// [
//     "プロジェクト1 スケジュール1",
//     "プロジェクト1 議事録1",
//     "プロジェクト2 スケジュール2",
//     "プロジェクト2 議事録2",
//     ...
// ]

IEnumerable<string> value = folders.SelectMany(
    (folder, index) => (index % 2 == 0) ? folder.Files : [],
    (folder, file) => $"{folder.Name} {file.Name}");
// [
//     "プロジェクト1 スケジュール1",
//     "プロジェクト1 議事録1",
//     "プロジェクト3 スケジュール3",
//     "プロジェクト3 議事録3",
// ]

SequenceEqual

2つのシーケンスが一致しているかどうかを判断します。要素の比較をカスタマイズする(IEqualityComparer<T>を実装したクラスを使う)こともできます。

int[] x = [1, 2, 3, 4, 5];
int[] y = [1, 2, 3, 4, 5];
bool value = x.SequenceEqual(y);
// true

int[] x = [1, 2, 3, 4, 5];
int[] y = [1, 2, 3, 4, 5];
bool value = x.SequenceEqual(y, EqualityComparer);
// IEqualityComparer<T> を実装したクラスで比較する

Single

要素の数が1の場合のみその要素を返します。条件を指定した場合は条件を満たす要素の数が1の場合のみその要素を返します。

int[] seq = [1];
int value = seq.Single();
// 1

int[] seq = [1, 2, 3, 4, 5];
int value = seq.Single();
// InvalidOperationException がスローされる

int[] seq = [1, 2, 3];
int value = seq.Single(element => element % 2 == 0);
// 2

SingleOrDefault

要素の数が1ならその要素、空なら既定値 (default(T)) を返します。条件を指定した場合は条件を満たす要素の数が1ならその要素、0なら既定値を返します。既定値を指定することもできます。

int[] seq = [1, 2, 3, 4, 5];
int value = seq.SingleOrDefault();
// InvalidOperationException がスローされる

int[] seq = [1, 3, 5, 7, 9];
int value = seq.SingleOrDefault(element => element % 2 == 0, -1);
// -1 (指定した既定値)

Skip

先頭から指定した数の要素を除いた部分シーケンスを返します

int[] seq = [1, 2, 3, 4, 5];
IEnumerable<int> value = seq.Skip(3);
// [4, 5]

int[] seq = [1, 2, 3, 4, 5];
IEnumerable<int> value = seq.Skip(10);
// []

SkipLast

最後から指定した数の要素を除いた部分シーケンスを返します

int[] seq = [1, 2, 3, 4, 5];
IEnumerable<int> value = seq.SkipLast(3);
// [1, 2]

int[] seq = [1, 2, 3, 4, 5];
IEnumerable<int> value = seq.SkipLast(10);
// []

SkipWhile

先頭から条件を満たして連続する要素を除いた部分シーケンスを返します

int[] seq = [2, 4, 6, 1, 3, 5];
IEnumerable<int> value = seq.SkipWhile(element => element % 2 == 0);
// [1, 3, 5]

int[] seq = [2, 4, 6, 1, 3, 5];
IEnumerable<int> value = seq.SkipWhile((element, index) => element > index);
// [1, 3, 5]

Sum

合計を返します。要素の型がnull許容型の場合、値がnullの要素は無視して、シーケンスが空かすべての要素の値がnullのときは0を返します。それぞれの要素から生成した結果の合計を返すこともできます。

int[] seq = [1, 2, 3, 4, 5];
int value = seq.Sum();
// 15

int[] seq = [];
int value = seq.Sum();
// 0

int?[] seq = [1, 2, 3, 4, null];
double? value = seq.Sum();
// 10 (null を除いた合計)

string[] seq = ["One", "Two", "Three", "Four", "Five"];
double value = seq.Sum(element => element.Length);
// 19 (文字数の合計)

Take

先頭から指定した数の要素のみを含む部分シーケンスを返します

int[] seq = [1, 2, 3, 4, 5];
IEnumerable<int> value = seq.Take(3);
// [1, 2, 3]

int[] seq = [1, 2, 3, 4, 5];
IEnumerable<int> value = seq.Take(10);
// [1, 2, 3, 4, 5]

TakeLast

最後から指定した数の要素のみを含む部分シーケンスを返します

int[] seq = [1, 2, 3, 4, 5];
IEnumerable<int> value = seq.TakeLast(3);
// [3, 4, 5]

int[] seq = [1, 2, 3, 4, 5];
IEnumerable<int> value = seq.TakeLast(10);
// [1, 2, 3, 4, 5]

TakeWhile

先頭から条件を満たして連続する要素のみを含む部分シーケンスを返します

int[] seq = [2, 4, 6, 1, 3, 5];
IEnumerable<int> value = seq.TakeWhile(element => element % 2 == 0);
// [2, 4, 6]

int[] seq = [2, 4, 6, 1, 3, 5];
IEnumerable<int> value = seq.TakeWhile((element, index) => element > index);
// [2, 4, 6]

ThenBy

OrderByと併用して、二次的に要素を昇順に並べ替えます。要素の比較をカスタマイズする(IComparer<T>を実装したクラスを使う)こともできます。

// 従業員クラス
class Employee {
    public int ID { get; set; }
    public string Dept { get; set; }
    public string Name { get; set; }
}
...
List<Employee> employees = [
    new() { ID = 1, Dept = "総務部", Name = "佐藤太郎" },
    new() { ID = 12, Dept = "総務部", Name = "鈴木花子" },
    new() { ID = 3, Dept = "総務部", Name = "高橋太郎" },
    new() { ID = 14, Dept = "人事部", Name = "田中花子" },
    new() { ID = 5, Dept = "人事部", Name = "伊藤太郎" }
];
IEnumerable<Employee> value = employees.OrderBy(element => element.Dept)
    .ThenBy(element => element.ID);
// [
//     { ID = 5, Dept = "人事部", Name = "伊藤太郎" },
//     { ID = 14, Dept = "人事部", Name = "田中花子" },
//     { ID = 1, Dept = "総務部", Name = "佐藤太郎" },
//     { ID = 3, Dept = "総務部", Name = "高橋太郎" },
//     { ID = 12, Dept = "総務部", Name = "鈴木花子" }
// ]

IEnumerable<Employee> value = employees.OrderBy(element => element.Dept)
    .ThenBy(element => element.ID, Comparer);
// IComparer<T> を実装したクラスで比較する

ThenByDescending

OrderByと併用して、二次的に要素を降順に並べ替えます。要素の比較をカスタマイズする(IComparer<T>を実装したクラスを使う)こともできます。

// 従業員クラス
class Employee {
    public int ID { get; set; }
    public string Dept { get; set; }
    public string Name { get; set; }
}
...
List<Employee> employees = [
    new() { ID = 1, Dept = "総務部", Name = "佐藤太郎" },
    new() { ID = 12, Dept = "総務部", Name = "鈴木花子" },
    new() { ID = 3, Dept = "総務部", Name = "高橋太郎" },
    new() { ID = 14, Dept = "人事部", Name = "田中花子" },
    new() { ID = 5, Dept = "人事部", Name = "伊藤太郎" }
];
IEnumerable<Employee> value = employees.OrderBy(element => element.Dept)
    .ThenByDescending(element => element.ID);
// [
//     { ID = 14, Dept = "人事部", Name = "田中花子" },
//     { ID = 5, Dept = "人事部", Name = "伊藤太郎" },
//     { ID = 12, Dept = "総務部", Name = "鈴木花子" },
//     { ID = 3, Dept = "総務部", Name = "高橋太郎" },
//     { ID = 1, Dept = "総務部", Name = "佐藤太郎" }
// ]

IEnumerable<Employee> value = employees.OrderBy(element => element.Dept)
    .ThenByDescending(element => element.ID, Comparer);
// IComparer<T> を実装したクラスで比較する

ToArray

シーケンスから配列を生成します。

int[] seq = [1, 2, 3, 4, 5];
int[] value = seq.Where(element => element % 2 == 0).ToArray();
// IEnumerable<int> から int 型配列に変換

ToDictionary

3つの機能があります。

  1. 2つの要素を持つタプルのシーケンスからDictionary<TKey,TValue>を生成します。
  2. KeyValuePair<TKey,TValue>のシーケンスからDictionary<TKey,TValue>を生成します。
  3. シーケンスからキーと値を指定してDictionary<TKey,TValue>を生成します。

キーの比較をカスタマイズする(IEqualityComparer<T>を実装するクラスを使う)ことができます。

// 機能1
(int, string)[] seq = [(1, "One"), (2, "Two"), (3, "Three"), (4, "Four"), (5, "Five")];
Dictionary<int, string> value = seq.ToDictionary();
// {
//     [1] = "One",
//     [2] = "Two",
//     [3] = "Three",
//     ...
// }

(int, string)[] seq = [(1, "One"), (2, "Two"), (3, "Three"),
    (1, "一"), (2, "二"), (3, "三")];
Dictionary<int, string> value = seq.ToDictionary();
// ArgumentException がスローされる

// 機能2
KeyValuePair<int, string>[] seq = [ new(1, "One"), new(2, "Two"), new(3, "Three"),
    new(4, "Four"), new(5, "Five") ];
Dictionary<int, string> value = seq.ToDictionary();
// {
//     [1] = "One",
//     [2] = "Two",
//     [3] = "Three",
//     ...
// }

// 機能3
// 従業員クラス
class Employee {
    public int ID { get; set; }
    public string Name { get; set; }
}
...
List<Employee> employees = [
    new() { ID = 1, Name = "佐藤太郎" },
    new() { ID = 2, Name = "鈴木花子" },
    new() { ID = 3, Name = "高橋太郎" },
    new() { ID = 4, Name = "田中花子" },
    new() { ID = 5, Name = "伊藤太郎" }
];
Dictionary<int, Employee> value = employees.ToDictionary(element => element.ID);
// {
//     [1] = { ID = 1, Name = "佐藤太郎" },
//     [2] = { ID = 2, Name = "鈴木花子" },
//     [3] = { ID = 3, Name = "高橋太郎" },
//     ...
// }

Dictionary<int, string> value = employees.ToDictionary(
    element => element.ID, element => element.Name);
// {
//     [1] = "佐藤太郎",
//     [2] = "鈴木花子",
//     [3] = "高橋太郎",
//     ...
// }

Dictionary<int, Employee> value = employees.ToDictionary(
    element => element.ID, EqualityComparer);
// IEqualityComparer<T>を実装するクラスで比較する

ToHashSet

シーケンスからHashSet<T>を生成します。要素の比較をカスタマイズする(IEqualityComparer<T>を実装するクラスを使う)ことができます。


int[] seq = [1, 2, 3, 4, 5];
HashSet<int> value = seq.ToHashSet();
// [1, 2, 3, 4, 5]

int[] seq = [1, 2, 3, 1, 2, 3];
HashSet<int> value = seq.ToHashSet();
// [1, 2, 3]

int[] seq = [1, 2, 3, 4, 5];
HashSet<int> value = seq.ToHashSet(EqualityComparer);
// IEqualityComparer<T>を実装するクラスで比較する

ToList

シーケンスからList<T>を生成します。

int[] seq = [1, 2, 3, 4, 5];
List<int> value = seq.ToList();
// int 型配列から List<int> に変換

ToLookup

シーケンスからILookup<TKey, TElement>を生成します。キーの比較をカスタマイズする(IEqualityComparer<T>を実装したクラスを使う)こともできます。

// 従業員クラス
class Employee {
    public string Dept { get; set; }
    public string Name { get; set; }
}
...
List<Employee> employees = [
    new() { Dept = "総務部", Name = "佐藤太郎" },
    new() { Dept = "総務部", Name = "鈴木花子" },
    new() { Dept = "総務部", Name = "高橋太郎" },
    new() { Dept = "人事部", Name = "田中花子" },
    new() { Dept = "人事部", Name = "伊藤太郎" }
];
ILookup<string, Employee> value = employees.ToLookup(
    employee => employee.Dept);
// [
//     {
//         Key = "総務部",
//         [
//             { Dept = "総務部", Name = "佐藤太郎" },
//             { Dept = "総務部", Name = "鈴木花子" },
//             { Dept = "総務部", Name = "高橋太郎" }
//         ]
//     },
//     {
//         Key = "人事部",
//         [
//             { Dept = "人事部", Name = "田中花子" },
//             { Dept = "人事部", Name = "伊藤太郎" }
//         ]
//     }
// ]

ILookup<string, Employee> value = employees.ToLookup(
    employee => employee.Dept,
    employee => employee.Name);
// [
//     { Key = "総務部", ["佐藤太郎", "鈴木花子", "高橋太郎"] },
//     { Key = "人事部", ["田中花子" "伊藤太郎"] }
// ]

ILookup<string, Employee> value = employees.ToLookup(
    employee => employee.Dept,
    EqualityComparer);
// IEqualityComparer<T>を実装したクラスで比較する

TryGetNonEnumeratedCount

列挙をせずに要素の数を返すことを試みます。関連するメソッド: CountLongCount

int[] seq = [1, 2, 3, 4, 5];
bool value = seq.TryGetNonEnumeratedCount(out int count);
// value: true
// count: 5

int[] seq = [1, 2, 3, 4, 5];
bool value = seq.Where(element => element % 2 == 0).TryGetNonEnumeratedCount(out int count);
// value: false (Where は遅延評価のため取得できない)

Union

2つのシーケンスの和集合※を返します。要素の比較をカスタマイズする(IEqualityComparer<T>を実装したクラスを使う)こともできます。

※2つのシーケンスX、Yにおいて、シーケンスXの要素にシーケンスYの要素を加えて、重複する要素を削除した内容になります。

int[] x = [1, 2, 3, 4, 5];
int[] y = [2, 4, 6];
IEnumerable<int> value = x.Union(y);
// [1, 2, 3, 4, 5, 6]

int[] x = [1, 2, 3, 4, 5];
int[] y = [2, 4, 6];
IEnumerable<int> value = x.Union(y, EqualityComparer);
// IEqualityComparer<T> を実装したクラスで比較する

UnionBy

指定したキーを比較して2つのシーケンスの和集合を返します。キーの比較をカスタマイズする(IEqualityComparer<T>を実装したクラスを使う)こともできます。

// 従業員クラス
class Employee {
    public int ID { get; set; }
    public string Dept { get; set; }
    public string Name { get; set; }
}
...
List<Employee> employees = [
    new() { ID = 1, Dept = "総務部", Name = "佐藤太郎" },
    new() { ID = 2, Dept = "総務部", Name = "鈴木花子" },
    new() { ID = 3, Dept = "人事部", Name = "高橋太郎" },
    new() { ID = 4, Dept = "人事部", Name = "田中花子" },
    new() { ID = 5, Dept = "経理部", Name = "伊藤太郎" }
];

IEnumerable<Employee> value = employees.Where(employee => employee.Dept == "総務部")
    .UnionBy(
        employees.Where(employee => employee.ID % 2 == 0),
        employee => employee.ID);
// [
//     { ID = 1, Dept = "総務部", Name = "佐藤太郎" },
//     { ID = 2, Dept = "総務部", Name = "鈴木花子" },
//     { ID = 4, Dept = "人事部", Name = "田中花子" }
// ]
// (総務部か ID が偶数の従業員)

IEnumerable<Employee> value = employees.Where(employee => employee.Dept == "総務部")
    .UnionBy(
        employees.Where(employee => employee.Dept == "人事部"),
        employee => employee.ID,
        EqualityComparer);
// IEqualityComparer<T> を実装したクラスで比較する

Where

条件を満たす要素のみを含む部分シーケンスを生成します。

int[] seq = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
IEnumerable<int> value = seq.Where(element => element % 2 == 0);
// [2, 4, 6, 8, 10] (偶数の要素)

int[] seq = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
IEnumerable<int> value = seq.Where(
    (element, index) => (element % 2 == 0) && (index >= seq.Count() / 2));
// [6, 8, 10] (後半の偶数の要素)

Zip

3つの機能があります。

  1. 2つのシーケンスからタプルのシーケンスを生成します。
  2. 3つのシーケンスからタプルのシーケンスを生成します。
  3. 2つのシーケンスからすべての要素で指定した関数を実行して結果のシーケンスを生成します。
// 機能 1
int[] x = [1, 2, 3, 4, 5];
string[] y = ["One", "Two", "Three"];
IEnumerable<(int, string)> value = x.Zip(y);
// [(1, "One"), (2, "Two"), (3, "Three")]

// 機能 2
int[] x = [1, 2, 3, 4, 5];
string[] y = ["One", "Two", "Three"];
string[] z = ["一", "二", "三"];
IEnumerable<(int, string, string)> value = x.Zip(y, z);
// [(1, "One", "一"), (2, "Two", "二"), (3, "Three", "三")]

// 機能 3
int[] x = [1, 2, 3, 4, 5];
string[] y = ["One", "Two", "Three"];
IEnumerable<string> value = x.Zip(y, (first, second) => $"{first} {second}");
// ["1 One",  "2 Two",  "3 Three"]

参照