Explain Linq Microsoft Select - Indexed [Example]

I am running from Microsoft 101 LINQ Samples , and I do not understand how this query knows how to assign the correct int value to the correct int field:

 public void Linq12() { int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; var numsInPlace = numbers.Select((num, index) => new { Num = num, InPlace = (num == index) }); Console.WriteLine("Number: In-place?"); foreach (var n in numsInPlace) { Console.WriteLine("{0}: {1}", n.Num, n.InPlace); } } 

I saw in SO # 336758 that there used to be errors in the examples, but it is much more likely that I just missed something.

Can someone explain this and how does the compiler know how to correctly interpret this data?

EDIT:

OK, I think my confusion comes from the LINQ extension, which allows you to work with the Select function. Func parameters and two int IEnumerable<TResult> IEnumerable<int>.Select(Func<int,int,TResult> selector) most likely the key to my lack of understanding.

enter image description here

+4
source share
6 answers

I'm not sure what you are asking, but Select iterates through the list, starting at index 0. If the value of the element in the current index is equal to the index, it will set the InPlace property in the anonymous object - true. I assume the above code will return true for 3, 6 and 7, right?

It will also simplify the explanation if you write something that you do not understand.

John Skeet wrote a series of blog posts where he implements linq, reads about Select here: Reimplementation of Select

UPDATE: I noticed one of the other comments in one of your comments, and it looks like it's lambda, not linq itself, which is confusing to you. If you read the Skeet blog post, you see that Select has two overloads:

 public static IEnumerable<TResult> Select<TSource, TResult>( this IEnumerable<TSource> source, Func<TSource, TResult> selector) public static IEnumerable<TResult> Select<TSource, TResult>( this IEnumerable<TSource> source, Func<TSource, int, TResult> selector) 

Select with index corresponds to the second overload. As you can see, this is an IEnumerable<TSource> extension, which in your case is an ints list, and so you call Select on IEnumerable<int> , and the signature of Select becomes: Select<int, TResult>(this IEnumerable<int> source, Func<int, int, TResult> selector) . As you can see, I changed TSource to int since it is a generic type of your IEnumerable<int> . I still have TResult since you are using an anonymous type. Could this explain some parts?

+6
source

Looks like me.

First you have an anonymous type with the creation of Num and InPlace. Then LINQ Select simply iterates over the elements with the element and the index of that element. If you have to rewrite it without linq and anonymous classes, it will look like this:

 class NumsInPlace { public int Num { get; set; } public bool InPlace { get; set; } } int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; List<NumsInPlace> numsInPlace = new List<int>(); for (int index = 0; i < numbers.length; i++) { int num = numers[index]; numsInPlace.Add(new NumsInPlace() { Num = num, InPlace = (index == num) }); } Console.WriteLine("Number: In-place?"); foreach (var n in numsInPlace) { Console.WriteLine("{0}: {1}", n.Num, n.InPlace); } 

MSDN on Enumerable.Select contains data, but the projection function (num, index) always has the element first, then the index second (if attached).

+2
source

The lambda expression (num, index) => new { Num = num, InPlace = (num == index) } is executed once for each element in the input sequence and passes the element and is indexed as arguments.

Update

Lambda expressions can be implicitly printed, that is, from the required type, the compiler can determine (or imply) what types of arguments you intend to be.

 (num, index) => new { Num = num, InPlace = (num == index) } 

equivalently

 someAnonymousType MyMethod(int num, int index) { return new { Num = num, InPlace = (num == index) }; } 

it is obvious that you cannot write the latter, because you cannot enter a name of an anonymous type, but the compiler can;)

The compiler knows this because the Select overload that you use takes Func<TSource, Int32, TResult> , it is Func that takes two arguments of type TSource (the type of your IEnumberable<T> , in this case int ) and Int32 (which represents index) and returns a TResult object, being what you want to return from your function, in this case, an anonymous type.

Lambda can be added to the required type, and so it just works.

+2
source

how does the compiler know that LINQ Select uses the index value as the index for the array?

The compiler does not know about index values. The implementation of this overload Select is aware of index values.

 //all the compiler sees is a method that accepts 2 int parameters and returns a bool. Func<int, int, bool> twoIntFunc = (x, y) => (x == y); //The compiler sees there an overload of Enumerable.Select which accepts such a method. IEnumerable<bool> query = numbers.Select(twoIntFunc); 

The Enumerable.Select implementation does the rest of the work by calling this method with the appropriate parameters.

The first argument to the selector represents the item to process. The second argument to the selector represents the zero index of this element in the original sequence.

So - Select will first call your method with (5, 0), then Select will call it with (4, 1).

+2
source

The second argument to select is the index, which increases when the compiler traverses an array of numbers. The compiler will see

 num index num = index 5 0 false 4 1 false 1 2 false 3 3 true 9 4 false 8 5 false 6 6 true 7 7 true 2 8 false 0 9 false 
+1
source

This is true for 3.6 and 7. It must be remembered that it starts with an index of 0.

0
source

All Articles