Linq でインデックスを参照する場合、Where と Select の順番には少し注意が必要です。
サンプルコード
public static void Main()
{
var persons = new List<Person>()
{
new Person{ Name = "Foo", Country = "Japan", Age = 10},
new Person{ Name = "Bar", Country = "Japan", Age = 20},
new Person{ Name = "Hoge", Country = "America", Age = 10},
new Person{ Name = "Piyo", Country = "America", Age = 20},
new Person{ Name = "Fuga", Country = "America", Age = 30},
};
foreach (var (p, i) in
persons
.Where(x => x.Country == "America")
.Where(x => x.Age > 15)
.Select((p, i) => (p, i)))
{
Console.WriteLine($"[{i}] {p.Name}, {p.Country}, {p.Age}");
}
Console.ReadKey();
}
public class Person
{
public string Name { get; set; }
public string Country { get; set; }
public int Age { get; set; }
}
出力結果
[0] Piyo, America, 20
[1] Fuga, America, 30
persons
の 3 番目と 4 番目の値が出力されますが、出力されたインデックスは 0 と 1 になっています。
これは、Where
でフィルタリングした結果に対して Select
しているためです。
分かっている人にとっては当たり前ですけどね。
元のインデックスを取得したい場合は?
for
文を使うとかありますけど、Linq でやるならば私が思いついたのは以下のようなコードです。
Select を先に持ってくる
Select
を先に持ってくると Where
でフィルタリングされる前なので、元のインデックスとなります。
タプルを使うので、C# 7.1 以上で使えます。
public static void Main()
{
var persons = new List<Person>()
{
new Person{ Name = "Foo", Country = "Japan", Age = 10},
new Person{ Name = "Bar", Country = "Japan", Age = 20},
new Person{ Name = "Hoge", Country = "America", Age = 10},
new Person{ Name = "Piyo", Country = "America", Age = 20},
new Person{ Name = "Fuga", Country = "America", Age = 30},
};
foreach (var (p, i) in
persons
.Select((p, i) => (p, i))
.Where(t => t.p.Country == "America")
.Where(t => t.p.Age > 15))
{
Console.WriteLine($"[{i}] {p.Name}, {p.Country}, {p.Age}");
}
Console.ReadKey();
}
public class Person
{
public string Name { get; set; }
public string Country { get; set; }
public int Age { get; set; }
}
出力結果
[3] Piyo, America, 20
[4] Fuga, America, 30