LoginSignup
3
8

More than 5 years have passed since last update.

配列(IEnumerable)の中から条件に当てはまる要素の添え字返却するLinq拡張

Last updated at Posted at 2017-04-03

使わないようで、意外と使うので作っておくと、ちょっと便利?

    public static class LinqExtensions
    {
        public static int FirstIndex<T>(this IEnumerable<T> ie, Predicate<T> match)
        {
            return ie.Select((tData, index) => new { tData, index }).First(arg => match(arg.tData)).index;
        }

        public static int? FirstIndexOrNull<T>(this IEnumerable<T> ie, Predicate<T> match)
        {
            return ie.Select((tData, index) => new { tData, index }).FirstOrDefault(arg => match(arg.tData))?.index;
        }
    }

使い方

    class Program
    {
        static void Main(string[] args)
        {
            //               [ 0][ 1][ 2][ 3][ 4][ 5][ 7][ 8][ 9][10][11][12]
            var list = new[] { 1,  2,  3,  4,  5, 10, 20, 31, 32, 33, 34, 35};

            var index1 = list.FirstIndex(i => i == 31);
            Console.WriteLine("31が格納されているのは:" + index1 + "番目の要素でした。");  //出力:31が格納されているのは:7番目の要素でした。

            var index2 = list.Select(i => i * 2).FirstIndex(i => i > 15);
            Console.WriteLine("2倍した値で初めて15を超えるのは:" + index2 + "番目の要素でした。");//出力:2倍した値で初めて15を超えるのは:5番目の要素でした。

            //var index3 = data.FirstIndex(i => i == 0);    // LinqのFirst同様、存在しない場合は "ハンドルされていない例外: System.InvalidOperationException: シーケンスに、一致する要素は含まれてません" の例外発生

            var index4 = list.FirstIndexOrNull(i => i == 0);    //見つからない可能性がある場合はFirstOrDefaultのようにFirstOrNullを使用
            if (index4.HasValue)
            {
                Console.WriteLine("0が格納されているのは:" + index4 + "番目の要素でした。");
            }
            else
            {
                Console.WriteLine("0は見つかりませんでした。");
            }
        }
    }

もちろんIEnumerable<T>なので

            var strList = new[] {"abc", "def", "ghijkl", "mnoprstu", "vwxyz"};
            var index5 = strList.FirstIndex(s => s.Length > 5);
            Console.WriteLine("文字数が5文字を超えるのは:" + index5 + "番目の要素でした。");//出力:文字数が5文字を超えるのは:2番目の要素でした。

の様に、stringや自前のクラスでもウッドボール。

ところがどっこい

ここまで書いて、検証処理ちょっと走らせていたらListクラスには最初からFindIndexってメソッドがある事に気付きました。
なので、

            var strList = new[] {"abc", "def", "ghijkl", "mnoprstu", "vwxyz"};
            var index6 = strList.ToList().FindIndex(s => s.Length > 5);
            Console.WriteLine("文字数が5文字を超えるのは:" + index6 + "番目の要素でした。");//出力:文字数が5文字を超えるのは:2番目の要素でした。

の様にToList()を挟んであげれば、わざわざ自前で拡張クラス作る必要もないんですね・・・(ToListのコストがあるので優位性が無いわけではない…? 中で匿名クラスがnewされてるからむしろ不利か…。)

基礎ができてないって辛い。

3
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
8