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("=========");
}
}
}
}
}
※上記のコードでは、ユーザが偶数人の場合に末尾にも「=====」が表示されてしまうのでちょっと微妙な実装ですが、、、そこは今回の内容とは別のところなので許してくださいまし。。。
コメント