LINQメソッドの使い方を用途ごとに簡単にまとめます。
LINQにどのようなメソッドが用意されているのかを把握しておくことで、コードを簡潔に書くことができます。
※本稿での「シーケンス」は「IEnumerable<T>」を指しています。
【検証環境】.NET Framework 4.7.2
要素の判定
Any
Any メソッドはシーケンスに要素が含まれているかを判定します。
//1~9のシーケンス生成
IEnumerable<int> nums = Enumerable.Range(1, 9);
//要素が存在するか
bool any = nums.Any(); // ⇒ true
//条件と一致する要素が存在するか
bool any_Condition = nums.Any(n => n == 1); // ⇒ true
All
All メソッドはシーケンスのすべての要素が条件に一致するかを判定します。
//1~9のシーケンス生成
IEnumerable<int> nums = Enumerable.Range(1, 9);
//指定した要素が存在するか
bool all = nums.All(n => n > 1); // ⇒ true
注意点として、シーケンスが空の場合はtrueを返します。All メソッドを使う場合はAny メソッドと組み合わせて使うことを推奨します。
//空のシーケンスを生成
IEnumerable<int> empty = Enumerable.Empty<int>();
//シーケンスが空だと無条件でtrueを返す
bool all = empty.All(n => n > 1); // ⇒ true
Contains
Contains メソッドはシーケンスに指定した要素が含まれるかを判定します。
//1~9のシーケンス生成
IEnumerable<int> nums = Enumerable.Range(1, 9);
//指定した要素が存在するか
bool contains = nums.Contains(0); // ⇒ false
SequenceEqual
SequenceEqualメソッドは2つのシーケンスが等しいかを判定します。
//1~9のシーケンス生成
IEnumerable<int> nums = Enumerable.Range(1, 9);
//比較用リスト生成
List<int> nums1 = new List<int>() { 9, 8, 7, 6, 5, 4, 3, 2, 1, };
List<int> nums2 = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, };
//2つのコレクションが等しいか
bool sequenceEqual1 = nums.SequenceEqual(nums1); // ⇒ false ※比較には順番も含まれる
bool sequenceEqual2 = nums.SequenceEqual(nums2); // ⇒ true
bool sequenceEqual3 = nums.SequenceEqual(nums1.OrderBy(n => n)); // ⇒ true ※整列して順序も合わせればtrue
単一要素の取得
First / FirstOrDefault
First / FirstOrDefault メソッドはシーケンスの最初の要素を返します。
それぞれの違いとして、シーケンスに要素が含まれていない場合に、First は例外エラーになりますが、FirstOrDefault は規定値(stringはnull、intは0…)を返します。Firstはシーケンスに要素が確実に存在する場合に使用します。
//1~9のシーケンス生成
IEnumerable<int> nums = Enumerable.Range(1, 9);
int first = nums.First(); // ⇒ 1
int firstOrDefault = nums.FirstOrDefault(); // ⇒ 1
//空のシーケンス生成
IEnumerable<int> empty = Enumerable.Empty<int>();
int firstEmp = empty.First(); // ⇒ <span class="red">例外エラー</span>
int firstOrDefaultEmp = empty.FirstOrDefault(); // ⇒ 0(規定値)
//条件指定も可能
int first_Condition = nums.First(n => n == 10);
int firstOrDefault_Condition = nums.FirstOrDefault(n => n == 10);
Last / LastOrDefault
Last /LastOrDefault メソッドはシーケンスの最後の要素を返します。
First / FirstOrDefaultと同様に、シーケンスに要素が含まれていない場合に、Lastは例外エラーになりますが、LastOrDefault は規定値(stringはnull、intは0…)を返します。Lastはシーケンスに要素が確実に存在する場合に使用します。
//1~9のシーケンス生成
IEnumerable<int> nums = Enumerable.Range(1, 9);
int last = nums.last(); // ⇒ 9
int lastOrDefault = nums.lastOrDefault(); // ⇒ 9
//空のシーケンス生成
IEnumerable<int> empty = Enumerable.Empty<int>();
int lastEmp = empty.last(); // ⇒ 例外エラー
int lastOrDefaultEmp = empty.lastOrDefault(); // ⇒ 0(規定値)
//条件指定も可能
int last_Condition = nums.last(n => n == 10);
int lastOrDefault_Condition = nums.lastOrDefault(n => n == 10);
Single / SingleOrDefault
Single/ SingleOrDefault メソッドはシーケンスの唯一の要素を返します。
First / FirstOrDefaultと同様に、シーケンスに要素が含まれていない場合に、Singleは例外エラーになりますが、SingleOrDefault は規定値(stringはnull、intは0…)を返します。Singleはシーケンスに要素が確実に1つだけ存在する場合に使用します。
//1~9のシーケンス生成
IEnumerable<int> nums = Enumerable.Range(1, 9);
int last = nums.last(); // ⇒ 9
int lastOrDefault = nums.lastOrDefault(); // ⇒ 9
//空のシーケンス生成
IEnumerable<int> empty = Enumerable.Empty<int>();
int lastEmp = empty.last(); // ⇒ 例外エラー
int lastOrDefaultEmp = empty.lastOrDefault(); // ⇒ 0(規定値)
//条件指定も可能
int last_Condition = nums.last(n => n == 10);
int lastOrDefault_Condition = nums.lastOrDefault(n => n == 10);
First と Singleはどちらもシーケンスから1つの要素を取得しますが、Singleは条件に一致する要素が複数存在すると例外エラーが発生します。Firstは複数あっても最初に見つかった要素を返します。
Singleはシーケンスの中に該当する要素が確実に1つの場合に使用します。
ElementAt / ElementAtOrDefault
ElementAt / ElementAtOrDefault メソッドは指定したインデックス位置の要素を返します。
First / FirstOrDefaultと同様に、シーケンスに要素が含まれていない場合に、ElementAtは例外エラーになりますが、ElementAtOrDefault は規定値(stringはnull、intは0…)を返します。ElementAtはシーケンスに要素が確実に存在する場合に使用します。
//1~9のシーケンス生成
IEnumerable<int> nums = Enumerable.Range(1, 9);
int elementAt = nums.ElementAt(5); // ⇒ 6
int elementAtOrDefault = nums.ElementAtOrDefault(5); // ⇒ 6
//空のシーケンス生成
IEnumerable<int> empty = Enumerable.Empty<int>();
int lelementAtEmp = empty.ElementAt(5); // ⇒ 例外エラー
int elementAtOrDefaultEmp = empty.ElementAtOrDefault(5); // ⇒ 0(規定値)
複数要素の取得
Select
Select メソッドは指定した要素を返します。(射影)
ラムダ式の第2引数を指定すると、要素のインデックスを返すことができます。
class Person
{
public string Name { get; set; }
public int Age { get; set; }
public static IEnumerable<Person> GetPerson()
{
return new List<Person>()
{
new Person()
{
Name = "ペン太",
Age = 25
},
new Person()
{
Name = "ペン子",
Age = 30,
},
new Person()
{
Name = "ホゲ助",
Age = 50,
}
};
}
}
static void Main(string[] args)
{
IEnumerable<Person> people = Person.GetPerson();
//Nameのシーケンスを取得
IEnumerable<string> select = person.Select(p => p.Name);
//匿名型でシーケンスを取得
var anonymous = person.Select(p => new { a = p.Name, b = p.Age, c = p.Height });
//要素とインデックスを取得
var select2 = person.Select((p, index) => (p.Name, index));
}
Where
Where メソッドは指定した条件と一致するシーケンスを返します。(フィルター処理)
//1~9のシーケンス生成
IEnumerable<int> nums = Enumerable.Range(1, 9);
int elementAt = nums.ElementAt(5); // ⇒ 6
IEnumerable<int> where = nums.Where(n => n > 5); // ⇒ 6, 7, 8, 9
Distinct
Distinct メソッドは一意の要素を返します。(重複を取り除く)
List<int> nums = new List<int>() { 1, 2, 2, 3, 3, 3,};
IEnumerable<int> distinct = nums.Distinct(); // ⇒ 1, 2, 3
Skip / SkipWhile
Skip / SkipWhileメソッドは任意の要素をスキップした残りの要素を返します。
Skipは引数にスキップする要素数を、SkipWhileは引数にスキップする条件を渡します。
//1~9のシーケンス生成
IEnumerable<int> nums = Enumerable.Range(1, 9);
//指定した数の要素をスキップして、残りの要素を返す
IEnumerable<int> skip = nums.Skip(5); // ⇒ 6, 7, 8, 9
//指定した条件と一致するまでスキップして、残りの要素を返す
IEnumerable<int> skipWhile = nums.SkipWhile(n => n < 5); // ⇒ 5, 6, 7, 8, 9
Take / TakeWhile
Take / TakeWhileメソッドは先頭から任意の要素を返します。
Takeは引数に先頭から取得する要素数を、TakeWhileは引数に先頭から取得する条件を渡します。
//1~9のシーケンス生成
IEnumerable<int> nums = Enumerable.Range(1, 9);
//先頭から指定した数の要素を返す
IEnumerable<int> take = nums.Take(5); // ⇒ 1, 2, 3 4, 5
//先頭から指定した条件と一致するまでの要素を返す
IEnumerable<int> takeWhile = nums.TakeWhile(n => n < 5); // ⇒ 1, 2, 3, 4
コレクションの生成
ToArray
ToArray メソッドはシーケンスから配列を生成します。
//1~9のシーケンス生成
IEnumerable<int> nums = Enumerable.Range(1, 9);
int[] toArray = nums.ToArray();
ToList
ToList メソッドはList<T>を生成します。
//1~9のシーケンス生成
IEnumerable<int> nums = Enumerable.Range(1, 9);
List<int> toList = nums.ToList();
ToDictionary
ToDictionary メソッドはシーケンスからDictionary<TKey, TValue>を生成します。
class Person
{
public string Name { get; set; }
public int Age { get; set; }
public static IEnumerable<Person> GetPerson()
{
return new List<Person>()
{
new Person()
{
Name = "ペン太",
Age = 25
},
new Person()
{
Name = "ペン子",
Age = 30,
},
new Person()
{
Name = "ホゲ助",
Age = 50,
}
};
}
}
static void Main(string[] args)
{
IEnumerable<Person> people = Person.GetPerson();
//NameをKeyに, 要素をValueにする場合 ※Valueを省略すると要素になる
Dictionary<string, Person> toDic = person.ToDictionary(key => key.Name);
//NameをKeyに、AgeをValueにする場合
Dictionary<string, int> toDictionary = person.ToDictionary(key => key.Name, value => value.Age);
}
ToLookup
ToLookup メソッドはシーケンスからILookup<TKey, TElement>を生成します。
ILookup型はDictionary型と同様に、キーを指定してアクセス可能です。違いとしてはDictionaryがキーを単一の値に割り振るのに対して、ILookupはキーを複数の要素に対して割り振ります。つまりグループ化をしているということです。
public static IEnumerable<Person> GetPerson()
{
return new List<Person>()
{
new Person()
{
Name = "ペン太",
Age = 25
},
new Person()
{
Name = "ペン太",
Age = 30,
},
new Person()
{
Name = "ホゲ助",
Age = 50,
}
};
}
static void Main(string[] args)
{
IEnumerable<Person> people = Person.GetPerson();
//Nameをキーにしてグループ化
ILookup<string, Person> toLookup = person.ToLookup(p => p.Name);
//キーが"ペン太"のシーケンスを取得
IEnumerable<Person> penta = toLookup["ペン太"]; // ⇒ Count = 2
}
Concat
Concat メソッドは2つのシーケンスどうしを連結したシーケンスを返します。
//1~9のシーケンス生成
IEnumerable<int> nums = Enumerable.Range(1, 9);
IEnumerable<int> concat = nums.Concat(Enumerable.Range(10, 5)); // 1,2,3,4,5,6,7,8,10,11,12,13,14
AddRangeとの違いについて
AddRangeはList型のメソッドで、ConcatはIEnumerable型の拡張メソッドです。
AddRangeは戻り値がvoidで対象のコレクションに追加しますが、Concatは戻り値に連結した新しいシーケンスを生成して返します。
統計
Count
Count メソッドはシーケンスの要素数を返します。
//1~9のシーケンス生成
IEnumerable<int> nums = Enumerable.Range(1, 9);
int count = nums.Count(); // ⇒ 9
Average
Average メソッドはシーケンスの平均値を返します。
//1~9のシーケンス生成
IEnumerable<int> nums = Enumerable.Range(1, 9);
double average = nums.Average(); // ⇒ 5
Sum
Sum メソッドはシーケンスの合計値を返します。
//1~9のシーケンス生成
IEnumerable<int> nums = Enumerable.Range(1, 9);
int sum = nums.Sum(); // ⇒ 45
Max / Min
Max メソッドはシーケンスの最大値を返します。
Min メソッドはシーケンスの最小値を返します。
//1~9のシーケンス生成
IEnumerable<int> nums = Enumerable.Range(1, 9);
int max = nums.Max(); // ⇒ 9
int min = nums.Min(); // ⇒ 1
並び替え
OrderBy / OrderByDescending
OrderByメソッドはシーケンスを昇順に並び替えて返します。
OrderByDescendingメソッドはシーケンスを降順に並び替えて返します。
※並び替え元のシーケンスの順序は変わりません。
public static IEnumerable<Person> GetPerson()
{
return new List<Person>()
{
new Person()
{
Name = "ペン太",
Age = 30
},
new Person()
{
Name = "ペン子",
Age = 25,
},
new Person()
{
Name = "ホゲ助",
Age = 50,
}
};
}
static void Main(string[] args)
{
//※personの順序は変わらない
//昇順
var orderBy = person.OrderBy(p => p.Age);
//降順
var orderByDescending = person.OrderByDescending(p => p.Age);
}
ThenBy / ThenByDescending
ThenByメソッドはOrderByのソート結果をさらに別のキーで昇順に並び替えて返します。
ThenByDescendingメソッドはOrderByのソート結果をさらに別のキーで降順に並び替えて返します。
class Person
{
public string Name { get; set; }
public int Age { get; set; }
//身長
public int Height { get; set; }
public static IEnumerable<Person> GetPerson()
{
return new List<Person>()
{
new Person()
{
Name = "ペン太",
Age = 25,
Height = 175,
},
new Person()
{
Name = "ペン子",
Age = 30,
Height = 150,
},
new Person()
{
Name = "ホゲ助",
Age = 50,
Height = 165,
}
};
}
}
static void Main(string[] args)
{
//※複数の条件を指定したい場合、2個目以降の条件はThenByで指定する
//昇順
var thenBy = person.OrderBy(p => p.Age)
.ThenBy(p => p.Height)
//降順
var thenByDescending = person.OrderBy(p => p.Age)
.ThenByDescending(p => p.Height);
}
Reverse
Reverse メソッドはシーケンスの要素の順序を反転します。
//1~9のシーケンス生成
IEnumerable<int> nums = Enumerable.Range(1, 9);
nums = nums.Reverse(); // ⇒ 9, 8, 7, 6, 5, 4, 3, 2, 1