Search code examples
c#closurescaptured-variable

How to compute rank of IEnumerable<T> and store it in type T


I want to compute rank of element in an IEnumerable list and assign it to the member. But below code works only when called 1st time. 2nd time call starts from last rank value. So instead of output 012 and 012, I'm getting 012 and 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
    }

I understand that the variable r is being captured (closure) and reused when called 2nd time. I don't want that behavior. Is there any clean way to compute rank and assign it? Also r variable (in actual code) isn't in the same scope where foreach loop is present. It is in a function which returns var first


Solution

  • var first = myArray.Select((s, i) => { s.Rank = i; return s; });