Unity - LINQについて③ -
初めに
C# を使う上で便利な LINQ についてまとめます。コレクション(配列や List など)の要素を処理するメソッドを集めたものになります。配列や List の並び替えや異なる配列などを合体させるときに使う関数をまとめます。
Index
LINQ とは
LINQ とは、C# で使われる統合言語クエリ(LINQ: Language-Integrated Query)と呼ばれるものになります。配列や List などの用をを処理する関数を集めたものです。
以前紹介した関数
(紹介した関数の一覧)
- All
- Any
- Contains
- OfType
- SequenceEqual
- Count
- First、FirstOrDefault
- Last、LastOrDefault
- Single、SingleOrDefault
- ElementAt、ElementAtDefault
- Skip、SkipWhile
- Take、TakeWhile
- DefaultIfEmpty
- Where
(紹介した関数の一覧)
- Max、Min
- Sum、Average
- Aggregate
- ToArray
- ToList
- ToDictionary
- AsEnumerable
- Cast
- Reverse
- Distinct
- Select
- SelectMany
LINQ の関数
OrderBy、OrderByDescending
配列や List 内の要素を昇順、降順に並び替える場合に使います。OrderBy は降順、OrderByDescending は昇順になります。
void Start() { int[] number = {4, 3, 6, 9, 1}; var result1 = number.OrderBy(x => x); //1, 3, 4, 6, 9 var result2 = number.OrderByDescending(x => x); //9, 6, 4, 3, 1 }
ThenBy、ThenByDescending
要素を並び替えた後、追加の条件で昇順に並べ替えます。
private List<hoge> hL_ = new List<hoge>(); void Start() { hL_.Add(new hoge { No=3, Name="五十嵐", Sex="M"}); hL_.Add(new hoge { No =2, Name = "伊藤", Sex="F"}); hL_.Add(new hoge { No =1, Name = "山本源流斎", Sex="M"}); var result = hL_.OrderBy(x => x.No).ThenByDescending(x => x.Name); foreach(hoge i in result) { Debug.Log(i.No + i.Name + i.Sex); //1山本源流斎, 2伊藤F, 3五十嵐M } } public struct hoge { public int No; public string Name; public string Sex; }
GroupBy
指定のキーで要素をグループ化します。
Pet[] pets = { new Pet { Name = "Pochi", Age = 4 }, new Pet { Name = "Tama", Age = 8 }, new Pet { Name = "Nyanko", Age = 1 }, new Pet { Name = "Wanko", Age = 1 } }; var result = pets.GroupBy(e => e.Age); // {Key = 4, Source = {{ Name = "Pochi", Age = 4 }}, // Key = 8, Source = {{ Name = "Tama", Age = 8 }}, // Key = 1, Source = {{ Name = "Nyanko", Age = 1 }, { Name = "Wanko", Age = 1 }}} } public class Pet { public string Name { get; set; } public int Age { get; set; } }
ToLookUp
特定のデータをキーにしてグループ分けします。
void Start() { Pet[] pets = { new Pet { Kind = "犬", Name = "Pochi", Age = 4 }, new Pet { Kind = "猫", Name = "Tama", Age = 8 }, new Pet { Kind = "猫", Name = "Nyanko", Age = 1 }, new Pet { Kind = "犬", Name = "Wanko", Age = 1 } }; var result = pets.ToLookup(e => e.Kind); foreach(var i in result) { Debug.Log(i.Key); //犬, 猫 var item = i.ToList(); foreach(var j in item) { Debug.Log(j.Kind + j.Name + j.Age); //犬Pochi4, 犬Wanko1, 猫Tama8, 猫Nyanko1 } } } public class Pet { public string Kind {get; set; } public string Name { get; set; } public int Age { get; set; } }
Concat
2つのシーケンスを連結します。
void Start() { Pet[] pets1 = { new Pet { Kind = "犬", Name = "Pochi", Age = 4 }, new Pet { Kind = "猫", Name = "Tama", Age = 8 }, new Pet { Kind = "猫", Name = "Nyanko", Age = 1 }, new Pet { Kind = "犬", Name = "Wanko", Age = 1 } }; Pet[] pets2 = { new Pet { Kind = "犬", Name = "Inu", Age = 10 }, new Pet { Kind = "猫", Name = "Neko", Age = 12 }, }; var result = pets1.Concat(pets2); foreach(var i in result) { Debug.Log(i.Kind + i.Name + i.Age); //犬Pochi4, 猫Tama8, 猫Nyanko1, 犬Wanko1, 犬Inu10, 猫Neko12 } } public class Pet { public string Kind {get; set; } public string Name { get; set; } public int Age { get; set; } }
Zip
複数の配列や List を合体させます。
void Start() { string[] names = {"あああ", "いいい", "ううう"}; int[] hp = {4, 2, 3}; var result = names.Zip(hp, (name, h) => new {Name = name, hp = h}); foreach(var k in result) { Debug.Log(k.Name + k.hp); //あああ4, いいい2, ううう3 } } public class Pet { public string Kind {get; set; } public string Name { get; set; } public int Age { get; set; } }
Join
一致するキーに基づいて、2つの配列を結合します。
void Start() { CharaName[] charaname = { new CharaName { Id = 1, Name = "あああ"}, new CharaName { Id = 2, Name = "いいい"}, new CharaName { Id = 3, Name = "ううう"}, }; CharaAge[] charaage = { new CharaAge { Id = 1, Age = 12}, new CharaAge { Id = 2, Age = 8}, new CharaAge { Id = 3, Age = 22}, }; var result = charaname.Join(charaage, name => name.Id, age => age.Id, (name, age) => new {name.Id, name.Name, age.Age}); foreach(var i in result) { Debug.Log(i.Id + i.Name + i.Age); //1あああ12, 2いいい8, 3ううう22 } } public class CharaName { public int Id {get; set; } public string Name { get; set; } } public class CharaAge { public int Id {get; set; } public int Age { get; set; } }
GroupJoin
Join によるデータの結合と GroupBy によるグループ化をまとめて行うことができます。
void Start() { CharaName[] charaname = { new CharaName { Id = 1, Name = "あああ"}, new CharaName { Id = 2, Name = "いいい"}, new CharaName { Id = 3, Name = "ううう"}, }; CharaAge[] charaage = { new CharaAge { Id = 1, Age = 12}, new CharaAge { Id = 2, Age = 8}, new CharaAge { Id = 3}, }; var result = charaname.GroupJoin(charaage, name => name.Id, age => age.Id, (name, age) => new {Id = name.Id, name = name.Name, age = age.DefaultIfEmpty() }) .SelectMany(x => x.age, (x, age) => new { Id = x.Id, Name = x.name, age = age != null ? age.Age : -1 }); foreach(var i in result) { Debug.Log(i.Id + i.Name + i.age); //1あああ12, 2いいい8, 3ううう0 } } public class CharaName { public int Id {get; set; } public string Name { get; set; } } public class CharaAge { public int Id {get; set; } public int Age { get; set; } }
Union, Except, Intersect
Union は2つの和集合、Except は差集合、Intersect は積集合を生成します。
int[] num1 = new[] {1, 3, 5, 7}; int[] num2 = new[] {1, 2, 7, 9}; var resultUnion = num1.Union(num2); //1, 3, 5, 7, 2, 9 var resultExcept = num1.Except(num2); //3, 5 var resultIntersect = num1.Intersect(num2); //1, 7
和集合は2つの要素を合わせた集合になります。差集合は共通部分を引いた集合になります。積集合は2つの集合の共通部分になります。
Empty
空の List を生成します。
Enumerable.Empty<型>() Debug.Log(Enumerable.Empty<int>().Count()); //0
Union をする際の中間値として利用することがあります。
Repeat
指定した要素を繰り返したシーケンスを返します。
// 中身が{ 1, 1, 1, 1 } のint[3] var numArray = Enumerable.Repeat( 1, 4 ).ToArray(); // 中身が{ 2, 2, 2, 2, 2 } のList<int> var numList = Enumerable.Repeat( 2, 5 ).ToList();
戻り値そのままだと IEnumerable のため使いづらいです。そのため、ToArray で配列に、ToList で List にしています。
Range
範囲内の連続した整数のシーケンスを作ります。
var seq1 = Enumerable.Range( 1, 4 ).ToArray(); //1, 2, 3, 4 var seq2 = Enumerable.Range( -10, 5 ).ToArray(); -10, -9, -8, -7, -6
第1引数は初期値、第2引数は生成する連続した整数の個数になります。
最後に
戻り値が IEnumerable になるなどして、そのままだと使いづらいです。そのため、ToArray や ToList を併用して使うようにしましょう。