Ari
Ari

Reputation: 3127

Changing variable in LINQ select

I'm converting one list to another. Additionally to data from first list I want to have position added. To do this I created following code:

class A
{
    ...
}

class B
{
    ...
    public int Position { get; set; }
}

List<A> listA = ...;
int pos = 1;
List<B> listB = listA.Where(...).Take(...).Select(
    a => new B { ..., Position = pos++ }).ToList();

It this working, but should it and will it always work? Is it safe to use such variable like pos in my code and change its value inside LINQ's Select?

Upvotes: 2

Views: 1052

Answers (1)

dcastro
dcastro

Reputation: 68660

You don't need pos. Select has an overload that takes a Func<T, int, TResult> as an argument, instead of Func<T, TResult>, where the int is the index of the element T.

listA.Select(
               (a, index) => new B { ..., Position = index}
            ).ToList();

Is it safe to use such variable like pos in my code and change its value inside LINQ's Select

In your concrete case, it is safe, mainly because you realize the list immediately (using ToList).

Generally, I'd advise against this. Here's why:

var collection = listA.Where(...).Take(...).Select(
    a => new B { ..., Position = pos++ });

foreach(var item in collection)
    Console.WriteLine(item.Position); //prints 0,1,2

foreach(var item in collection)
    Console.WriteLine(item.Position); //prints 3,4,5

LINQ is stateless. It's supposed to be pure, as in, for the same input, you should always get the same output. By making the lambda dependent on a mutable variable, you're giving up this very important property.

Upvotes: 6

Related Questions