3

I'm not sure if this is the right place to ask this, I'm sorry if not.

using the same code as in:

C# LINQ expression question

string[] digits = { "zero", "one", "two", "three", "four", "five", 
                    "six", "seven", "eight", "nine" };
var shortDigits = digits.Where((digit, index) => digit.Length < index);
foreach (var sD in shortDigits)
{
    Console.WriteLine(sD);
}
// Output:
// five
// six
// seven
// eight
// nine

How does the system know that, digit are the items in digits, and index the position within the array?

Community
  • 1
  • 1
Somebody
  • 2,667
  • 14
  • 60
  • 100

4 Answers4

6

That particular overload of the Where extension method is defined to accept a Func where the first parameter is the element and the second parameter is the index of that element. This is mentioned explicitly in the documentation:

predicate

Type: System.Func<TSource, Int32, Boolean>

A function to test each source element for a condition; the second parameter of the function represents the index of the source element.

Emphasis mine.

Community
  • 1
  • 1
Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
2

This is just a naming thing, you could name digit anything, and index anything. This is just a lambda expression for an anonymous function...it could be rewritten:

(string digit, int index) => digit.Length < index

so, the names are the same as any parameter you normally set up in a method. There is nothing truly special about the names being recognized by the C# engine.

(string index, int digit) => index.Length < digit

The above would work also...it would be confusing, but it would work. It is just to show that the name can be whatever you want

If you are referring how to the signature itself then it is due to an overload of the Where function

public static IEnumerable<TSource> Where<TSource>(
    this IEnumerable<TSource> source,
    Func<TSource, int, bool> predicate
)

So, the TSource in this case is string, making the Func become Func<string, int, bool>. Meaning that the lambda must take a string parameter followed by an int param, and return a bool value

Justin Pihony
  • 66,056
  • 18
  • 147
  • 180
  • His question was on why the first parameter represented the item in the collection and the second its index... not their names. – Jeff Mercado Jul 10 '12 at 16:12
  • I can read it both ways, so will wait for the OP to clarify...meanwhile I will answer for both possibilities – Justin Pihony Jul 10 '12 at 16:14
1

The overload of Where that you are using is implemented like this:

public static IEnumerable<T> Where<T>(
      this IEnumerable<T> list, Func<T,int,bool> predicate)
{
   int num = -1;
   foreach (T current in list)
   {
      num++;
      if (predicate(current, num))
      {
         yield return current;
      }
   }
   yield break;
}

as you can see, on each iteration, the predicate (i.e. the passed lambda expression) is invoked passing the current element of the list and the current index.

In this way, the code in the lambda expression know both the element and its index.

digEmAll
  • 56,430
  • 9
  • 115
  • 140
0

Because there is an overload of where taking as a predicate a function like this:

Func<TSource, int, bool>

the semantic of this predicate ios defined so the second parameter is the index. So if you pass a lambda with two args that version of where is called.

Felice Pollano
  • 32,832
  • 9
  • 75
  • 115