【C#】foreach文でもindexは使用できる!

Select()を使うことで、foreach文内でインデックス(何番目の要素か?)を使用できる!

コレクション(配列やリスト)の各要素を使って何かしらの処理を行いたいとき、foreach文を使うことでfor文に比べて簡潔に書くことができます。

// for文
for(var i = 0; i < list.Count(); i++)
{
    var item = list[i];   // ←ここ面倒ポイント

    // ~処理~
}

// foraech文
foreach(var item in list)
{
    // for文のようにインデクサを使って要素を取得しなくて良い!ラクちん

    // ~処理~
}

しかし、foreach文では単純にコレクションの要素を1つずつ取り出して処理するという動きをするため、その要素がコレクションにおいて何番目なのか(インデックス)を取得することができないように見えます。


// foraech文
foreach(var item in list)
{
    // for文のようにインデクサを使って要素を取得しなくて良い!ラクちん
    // でもインデックス(何個目の要素か)は分からない...><

    // ~処理~
}

では、何番目の要素かが知りたいとき(インデックスを使いたいとき)はfor文を使うしかないのでしょうか?

実はそんなことはなく、LINQのSelect()と組み合わせることでインデックスを使用することができます。


// foraech文
foreach(var (item, index) in list.Select((x, i) => (x, i)))
{
    // item ・・・ listの各要素
    // index・・・ 何個目の要素か

    // ~処理~
}

上記のようにSelect()を使うことで、foreach文内で「何番目の要素か(インデックス)」と「要素」をセットで使うことができます。

なお、このindexは0始まりになります。つまり、最初のループではindex=0であり、2番目のループではindex=1になります。ここは配列やリストのインデックスと同じですね。

■参考

Enumerable.Select メソッド (System.Linq)
シーケンスの各要素を新しいフォームに射影します。

実際に使ってみた

下記は、ユーザー情報を2人ごとに「=====」で区切って表示するコードです。

こんな感じに出力されます。

Name:たまご, Age:0
Name:ひよこ, Age:2
=========
Name:にわとり, Age:4
Name:おたまじゃくし, Age:1
=========
Name:カエル, Age:3

↓コード

namespace ForeachIndex
{
    public class Program
    {
        /// <summary>
        /// ユーザー情報
        /// </summary>
        public class User
        {
            /// <summary>
            /// 名前
            /// </summary>
            public String Name { get; set; }

            /// <summary>
            /// 年齢
            /// </summary>
            public int Age { get; set; }
        }

        /// <summary>
        /// エントリポイント
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            // ユーザー情報リストの作成
            var users = new User[]
            {
                new User{ Name = "たまご", Age = 0 },
                new User{ Name = "ひよこ", Age = 2 },
                new User{ Name = "にわとり", Age = 4 },
                new User{ Name = "おたまじゃくし", Age = 1 },
                new User{ Name = "カエル", Age = 3 },
            };

            foreach (var (user, index) in users.Select((x, i) => (x, i)))
            {
                // ユーザー情報の表示
                Console.WriteLine($"Name:{user.Name}, Age:{user.Age}");

                // 2人ごとに「======」で区切る
                if ((index + 1) % 2 == 0)
                {
                    Console.WriteLine("=========");
                }
            }
        }
    }
}

※上記のコードでは、ユーザが偶数人の場合に末尾にも「=====」が表示されてしまうのでちょっと微妙な実装ですが、、、そこは今回の内容とは別のところなので許してくださいまし。。。

コメント