Как вычислить ранг IEnumerable<T> и сохранить его в типе T
Я хочу вычислить ранг элемента в списке 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
3 ответа
var first = myArray.Select((s, i) => { s.Rank = i; return s; });
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;
});
Вы не должны использовать 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++;
}