はじめに
今回はLINQと要素のインデックスについて掘り下げてみる記事になります!
以下のコードを少し見てみてください。
IEnumerable<string> names = new[] { "スライム", "ももんじゃ", "ドラキー" }; Debug.Log(names[1]);
なんとなくやりたい事が分かると思いますが、コレクションの2番目の要素を出力しようとしています。
でも残念、names[1]
のような書き方をするとエラーが出てきてしまうんですよね。
配列やリストなどはインデクサーと呼ばれる機能があるのでこれができるのですが、かならずしもコレクションにこの機能があるとは限りません。
【Unity】インデクサーについてかるくまとめてみた - はなちるのマイノート
これについて少し掘り下げていきたいと思います。
指定したインデックスの要素を取得する
LINQにはElementAt
というメソッドがあります。これで指定したインデックスの要素を取得することができます。
IEnumerable<string> names = new[] { "スライム", "ももんじゃ", "ドラキー" }; print(names.ElementAt(1)); //ももんじゃ
配列のarray[1]
とElementAt(1)
は同じ番号を示すのでとても分かりやすいですね。
ちなみに不正なインデックスが与えられたらデフォルト値を返してくれるElementAtDefault
というメソッドも存在します。
インデックスを取得する
つぎにこのコードをみてみてください。
string[] names = { "スライム", "ももんじゃ", "ドラキー" }; print(Array.IndexOf(names, "ももんじゃ")); //1 List<string> names = new List<string> { "スライム", "ももんじゃ", "ドラキー" }; print(names.IndexOf("ももんじゃ")); //1
これは要素からインデックスを取得しています。
ただLINQにはその機能はないみたいなので、少しだけ工夫が必要です。
私が見つけたものはSelect
メソッドのオーバーロードを用いて匿名クラスを作成してしまうという方法でした。
IEnumerable<string> names = new[] { "スライム", "ももんじゃ", "ドラキー" }; var monsters = names.Select((p, i) => new { Name = p, Index = i }); //名前とインデックスを関連付ける print(monsters.Where(p => p.Name == "ももんじゃ").First().Index); //1
結構長くなってしまいましたが、これでIndexOf
と同様に用いることができます。
さいごに
私が聞いた限りではIEnumerable
インターフェイスには要素の順序の概念がないと言われていましたが、LINQ(IEnumeralbeの拡張メソッド)を用いることで要素の順序を扱うことができてしまいました。
これって実質順序の概念があるともいえると思うのですが、果たしてどうなのでしょうか・・・。