我想计算IEnumerable列表中元素的等级并将其分配给成员。但是下面的代码仅在第一次调用时起作用。第二次通话从最后一个等级值开始。所以我没有输出012和012,而是得到012和345
class MyClass
{
public string Name { get; set; }
public int Rank { get; set; }
}
public void SecondTimeRankEvaluvate()
{
MyClass[] myArray = new MyClass[]
{
new MyClass() { Name = "Foo" },
new MyClass() { Name = "Bar" },
new MyClass() { Name = "Baz" }
};
int r = 0;
var first = myArray.Select(s => { s.Rank = r++; return s; });
foreach (var item in first)
{
Console.Write(item.Rank);
}
// Prints 012
Console.WriteLine("");
foreach (var item in first)
{
Console.Write(item.Rank);
}
// Prints 345
}
我理解变量r
被捕获(闭包)并在第二次调用时重用。我不希望这种行为。是否有任何干净的方法来计算排名并分配它?
此外,r
变量(在实际代码中)与foreach
循环存在的范围不同。它在一个返回var first
答案 0 :(得分:5)
var first = myArray.Select((s, i) => { s.Rank = i; return s; });
答案 1 :(得分:3)
LINQ使用延迟评估并在每次使用Select
时运行myArray
部分。
通过将结果存储在List
。
更改
var first = myArray.Select(s => { s.Rank = r++; return s; });
到
var first = myArray.Select(s => { s.Rank = r++; return s; }).ToList();
另一种方法是每次使用myArray
加入Zip
新序列,例如
var first = myArray.Zip(Enumerable.Range(0, int.MaxValue), (s, r) =>
{
s.Rank = r;
return s;
});
答案 2 :(得分:1)
如果您没有查询集合,则不应使用LINQ。
要更新数组中的每个项目,请使用for
循环:
for (int i = 0; i < myArray.Length; i++)
{
myArray[i].Rank = i;
}
要更新可枚举项中的每个项目,请使用foreach
循环:
int r = 0;
foreach (var item in myArray)
{
item.Rank = r++;
}