記事のカテゴリー: C#、.NET 9
LINQ拡張メソッド(System.Linq名前空間のEnumerableクラスに宣言された拡張メソッド、静的メソッド)について、概要と使用例をまとめています。文中ではIEnumerable<T>オブジェクトをシーケンスと呼んでいます。
インデックス
シーケンスの生成
DefaultIfEmpty、Empty(静的メソッド)、Range(静的メソッド)、Repeat(静的メソッド)
部分シーケンスの生成
Skip、SkipLast、SkipWhile、Take、TakeLast、TakeWhile、Where
シーケンスの変換
AsEnumerable、Cast、Index、OfType、ToArray、ToDictionary、ToHashSet、ToList、ToLookup、Zip
操作
Chunk、Concat、GroupBy、GroupJoin、Join、Select、SelectMany、TryGetNonEnumeratedCount
要素の操作
Append、ElementAt、ElementAtOrDefault、First、FirstOrDefault、Last、LastOrDefault、Prepend、Single、SingleOrDefault
判断
All、Any、Contains、SequenceEqual
集計
Aggregate、Average、Count、LongCount、Max、MaxBy、Min、MinBy、Sum
集合演算
Distinct、DistinctBy、Except、ExceptBy、Intersect、IntersectBy、Union、UnionBy
並べ替え
Order、OrderBy、OrderByDescending、OrderDescending、Reverse、ThenBy、ThenByDescending
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
要素の数を返します。条件を指定した場合は条件を満たす要素の数を返します。関連するメソッド: LongCount、TryGetNonEnumeratedCount
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つの機能があります。
- 指定したキーでグループ化して、それらのグループのシーケンスを生成します。
- 指定したキーでグループ化して、すべてのグループで指定した関数を実行して、結果のシーケンスを生成します。
キーの比較をカスタマイズする(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型で返します。条件を指定した場合は条件を満たす要素の数を返します。関連メソッド: Count、TryGetNonEnumeratedCount。
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
// フォルダークラス
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つの機能があります。
-
2つの要素を持つタプルのシーケンスから
Dictionary<TKey, TValue>を生成します。 -
KeyValuePair<TKey, TValue>のシーケンスからDictionary<TKey, TValue>を生成します。 -
シーケンスからキーと値を指定して
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
列挙をせずに要素の数を返すことを試みます。関連するメソッド: Count、LongCount
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つの機能があります。
- 2つのシーケンスからタプルのシーケンスを生成します。
- 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"]



0 件のコメント:
コメントを投稿