LINQ: where and select clauses

In the last post, we gave an overview of LINQ and started coding with a simple example. In this post, we’ll take a closer look at two of the most commonly used clauses: where and select.

We saw select used in the last post, but it can do a few more things than we showed there. We’ll illustrate it by using the same sample data structure: a list of Canada’s prime ministers. In our previous example, we just printed out a list of all the prime ministers. This time, we’d like to select just those prime ministers whose first name is John. We can do this either by using a query expression or the standard query operators. First, the query expression:

      var pmList3 = from pm in primeMinisters
                    where pm.firstName.Equals("John")
                    select pm;
      foreach (PrimeMinisters pm in pmList3)
      {
        Console.WriteLine(pm);
      }

As before, the ‘from’ clause enumerates all the elements in primeMinisters, returning each element in turn as the variable pm. The elements are fed into the ‘where’ clause where they are tested against the condition that pm.firstName must be “John”. The argument of a ‘where’ can be any boolean expression. Finally, we use ‘select’ as before to yield the original object pm. Thus this expression will filter out those elements of primeMinisters such that pm.firstName is John.

Note that we’ve specified the returned value pmList3 as a ‘var’, rather than giving an explicit data type as we did last time. In this case, we could have stated the data type explicitly since we know it must be IEnumerable<PrimeMinisters>, but ‘var’ is a lot easier to type. Remember that ‘var’ creates a new object giving it the data type of whatever object is first assigned to it.

The output of this code is

1. John Macdonald (Conservative)
3. John Abbott (Conservative)
4. John Thompson (Conservative)
13. John Diefenbaker (Conservative)
17. John Turner (Liberal)

Now we’ll look at how to write the same code using standard query operators. We get

      var pmList4 = primeMinisters.Where(pm => pm.firstName.Equals("John"));
      foreach (PrimeMinisters pm in pmList4)
      {
        Console.WriteLine(pm);
      }

The ‘where’ clause is essentially the same, except that we have to use a lambda expression to specify the predicate. Note, though, that here we don’t need a call to ‘Select()’ to finish the command off. If you think about it, the call to select in the query expression above is redundant (or should be) since all it does is just return everything produced by the ‘where’ clause. However, all query expressions demand a ‘select’ at the end, so we have to put one in.

The contents of pmList4 are the same as pmList3.

Next, a brief illustration of a compound predicate in the ‘where’ clause. We want a list of prime ministers whose first name is John and who are Conservative. We get (showing both the query expression and standard query forms):

      var pmList5 = from pm in primeMinisters
                    where pm.firstName.Equals("John") && pm.party.Equals("Conservative")
                    select pm;
      foreach (PrimeMinisters pm in pmList5)
      {
        Console.WriteLine(pm);
      }

      var pmList6 = primeMinisters.Where(pm => pm.firstName.Equals("John") && pm.party.Equals("Conservative"));
      foreach (PrimeMinisters pm in pmList6)
      {
        Console.WriteLine(pm);
      }

To combine boolean expressions, we use the usual logical operators from C#: && for a logical AND and || for a logical OR. The predicate can consist of as many of these statements as you want to string together.

The output of both of these bits of code is:

1. John Macdonald (Conservative)
3. John Abbott (Conservative)
4. John Thompson (Conservative)
13. John Diefenbaker (Conservative)

Now we’ll branch out a bit and see what else the ‘select’ can do. In the next example, we again look for men named John, but this time we want to print out only the id and last name of each man. We could do this in the WriteLine call of course by merely selecting the corresponding fields, but let’s do it slightly differently. We’ll have ‘select’ construct an object from an anonymous class that contains just the two bits of data we want. Here’s the code in both forms:

      var pmList7 = from pm in primeMinisters
                    where pm.firstName.Equals("John")
                    select new
                    {
                      id = pm.id,
                      surname = pm.lastName
                    };
      foreach (var name in pmList7)
      {
        Console.WriteLine(name);
      }

      var pmList8 = primeMinisters.Where(pm => pm.firstName.Equals("John")).
                    Select(pm => new
                    {
                      id = pm.id,
                      surname = pm.lastName
                    });
      foreach (var name in pmList8)
      {
        Console.WriteLine(name);
      }

We construct an object with an ‘id’ and ‘surname’ fields for each ‘pm’ object that passes through the ‘where’ filter. In the query expression, we can use ‘pm’ straight off since the same object is available all the way through the expression. In the standard query form, we need to provide a lambda expression for ‘select’, as before. The output of either of these queries is

{ id = 1, surname = Macdonald }
{ id = 3, surname = Abbott }
{ id = 4, surname = Thompson }
{ id = 13, surname = Diefenbaker }
{ id = 17, surname = Turner }

In this case, we must use ‘var’ to declare the result of the query, since this result is an IEnumerable list containing objects of an anonymous type, so we don’t know what this type is called internally. However, we do know that each object has an ‘id’ field and a ‘surname’ field, so we can access those if we want. In this example, though, we’ve just printed out the bare object so you can see what happens. When an anonymous object is printed, we get all the fields and their values printed out and enclosed by braces.

The ‘select’ clause has a second form, in which the function that is passed to it contains two arguments rather than the single one we’ve seen so far. In this case, the second argument is the index of the object in the sequence that is passed into the Select() method. If we want to use this form of Select(), we must use the standard query notation as there is no equivalent in a query expression.

As an example, we want to select all men named John and produce a numbered list where the numbers are sequential, rather than the id numbers from the original list. We have

      var pmList9 = primeMinisters.Where(pm => pm.firstName.Equals("John")).
                    Select((pm, index) => new
                    {
                      id = index + 1,
                      surname = pm.lastName
                    });
      foreach (var name in pmList9)
      {
        Console.WriteLine(name);
      }

Note that two arguments are provided in the lambda expression. The ‘index’ is the zero-based index of the element ‘pm’ in the input sequence. We again construct an anonymous object, adding 1 to ‘index’ so we get a 1-based sequence as output. The output is

{ id = 1, surname = Macdonald }
{ id = 2, surname = Abbott }
{ id = 3, surname = Thompson }
{ id = 4, surname = Diefenbaker }
{ id = 5, surname = Turner }

The Where() method also has a two-argument form, where the second argument is the zero-based index of each element in the sequence that is input into the Where(). It too can be used only in standard query form.

Advertisements
Post a comment or leave a trackback: Trackback URL.

Trackbacks

  • By LINQ: SelectMany « Programming tutorials on May 18, 2012 at 5:55 PM

    […] LINQ Select command that we’ve used so far returns a single object for each input object that is passed to it. In some cases, we would like to […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: