Projection Operators in LINQ

Projection Operators transforms the results of a query into a new form. The type in which these results are transformed are defined by the developers.

There are the following two types of Projection Operators:

  1. Select
  2. SelectMany

Let's understand these operators using an example.

1. Select Operator

If you want to select values from a single collection, then use the Select Operator.

Let's say we have a class Student with these five auto-implemented properties:

properties

There is another class in the same cs file, in which there is a Main method from where the execution of every program starts.

We will create four separate objects of the Student class and we will add these objects to a list.

  1. class MainProgram {  
  2. static void Main (string[] args) {  
  3.    //student object one  
  4.    Student studentOne = new Student {  
  5.    StudentId = 201,  
  6.    FirstName = "Sam",  
  7.    LastName = "Fisher",  
  8.    Gender ="Male",  
  9.    TotalMarks = 450  
  10. };  
  11.   
  12. //student object two  
  13. Student studentTwo = new Student {  
  14.    StudentId = 205,  
  15.    FirstName = "Max",  
  16.    LastName = "Payne",  
  17.    Gender ="Male",  
  18.    TotalMarks = 300.55  
  19. };  
  20.   
  21. //student object three  
  22. Student studentThree = new Student {  
  23.    StudentId = 210,  
  24.    FirstName = "Lara",  
  25.    LastName = "Croft",  
  26.    Gender ="Female",  
  27.    TotalMarks = 407.87  
  28. };  
  29.   
  30. //student object four  
  31. Student studentFour = new Student {  
  32.    StudentId = 250,  
  33.    FirstName = "Aiden",  
  34.    LastName = "Pearce",  
  35.    Gender ="Male",  
  36.    TotalMarks = 495  
  37. }; 

Create a list collection of type Student and add these four Student objects to it.

collection

Demo 1

Let's say we want to retrieve all the StudentIds from the StudentList.

We can say StudentList.Select(

StudentList

Look at the first overloaded version of this Select operator parameter, it expects an object of type student. So, we can pass a lambda expression and based on the expression the result type will be decided and since we want to return a StudentId, so the TResult type will be an integer.

StudentList.Select(s => s.StudentId); //where s is a parameter of type student and s.StudentId is an expression

Look at the type, this Select function (Operator) is returning.

Select function

It returns an IEnumerable of integer but what will happen if I change the expression from s.StudentId to s.FirstName?

IEnumerable

This time it returns an IEnumerable of string. So, based on the expression we pass, the result type TResult is assigned.

So, let's change it back to s.StudentId. Create a new IEnumerable<int> object and assign the result to it.

  1. IEnumerable<int> Ids = StudentList.Select(s => s.StudentId); 

To retrieve all the Student Ids from this Ids object, we can use a foreach loop.

  1. foreach (var Id in Ids) {  
  2.    Console.WriteLine("Student Id {0}",String.Concat(Id));  

Run the application.

Run

Demo 2

Let's say we want all the student ids but with the student ids we want their index position too.

For that we can use the second overloaded version of this Select function (operator) that expects two parameters. The first parameter is the type of list and here the type is Student and the second parameter is of type integer.

operator

Look at the type of StudentId that we passed as a first parameter.

StudentId

It states that StudentId is of type Student.

Look at the type that we passed as a second parameter.

passed as a second parameter

It states i is of type integer.

So, we have passed the two required types of parameters and now it is time to pass an expression and the return type of the Select function will be based on the type of expression we pass in.

  1. StudentList.Select((StudentId, i) => new { Id = StudentId, Index = i }); 

This new { Id = StudentId, Index = i } is nothing but a new anonymous type of Student and integer. Using the projection operator the result query are transformed into a new form.

projection

Now you might be wondering whether based on the expression we pass, the TResult type is assigned and now the result type is anonymous so in which type of object we can store the result.

If you hover your mouse over the Select function, you will see this function returns an IEnuemrable<a> object back.

function returns

Which means we can store the value in this type.

But when we try to create an object of that type, we don't get any suggestions.

create an object

And when we hard-code it, we get an error.

So, in which type of object can we assign the anonymous type?

Whenever a function returns an anonymous type back, we can create a var type object.

  1. var anonymous = StudentList.Select((StudentId, i) => new { Id = StudentId, Index = i }); 

If you hover your mouse on an anonymous var object, you will see this object is of type IEnumerable<a>. The type of this var object is derived based on the type of object we are assigning in it.

object

The next step is to retrieve the StudentId and Index and for that we can use a foreach loop.

  1. foreach (var item in anonymous) {  
  2.    Console.WriteLine("Student Id = {0}, Index Position = {1}"string.Concat(item.Id.StudentId), string.Concat(item.Index));  

The anonymous type Id is basically an anonymous student object and using that we will get all the properties.

get all the properties

Run the application.

output

Demo 3

Let's say we want to display the StudentId, FirstName and LastName concatenated as FullName, Gender and TotalMarks with the percentage of all the students.

TotalMarks

Using the Student object stud we have created a new anonymous type objects.

Id, FullName, Gender, TotalMarks, Percentage.

The value for these anonymous types are coming from the stud Student object.

  • Id = stud.StudentId => we are assigning the student id value in this new anonymous type.

  • FullName = stud.FirstName + “ “ + stud.LastName => we are concatenating both the FirstName and LastName and assigning the result to the FullName that is a new anonymous type.

  • Gender = stud.Gender => Just like StudentId we are assigning the Gender to the new anonymous type and the same goes for the TotalMarks TotalMarks = stud.TotalMarks.

Since these marks are of five subjects and to get the percentage we created a new anonymous type “Percentage” and assigned this expression stud.TotalMarks/5 + "%" that will provide us the percentage back and now all we need to do is loop using each anonymous type.

  1. foreach (var item in AllRecords) {
  2.  
  3.     Console.WriteLine("Student Id = {0},Student Name = {1},Gender = {2},Total Marks = {3},Percentage = {4}",item.Id,item.FullName,item.Gender,item.TotalMarks,item.Percentage);  
  4. }  
  5. #endregion 

Run the application.

percentage

Summary

Just like the Select clause in SQL Server, using which we can select a specific column or multiple columns. In LINQ too we can do the same using the Select operator where we can select a specific property, multiple properties and in addition to that we can also do some calculations.

2. SelectMany

If you want to select values from a multiple collection, then use the SelectMany operator, meaning if you want the result from a list of lists and want to display as in a single sequence then the SelectMany operator can be very useful.

Let's say we have a class Student with five auto-implemented properties.

implemented properties

Out of these five properties, “Subject” is of type List<string> meaning it is a collection of strings.

Within the same cs file, I have another class MainProgram in which there is a Main method in which we will create four objects of this class.

  1. static void Main (string[] args) {  
  2.     //student object one  
  3.     Student studentOne = new Student {  
  4.         StudentId = 201,  
  5.         FirstName = "Sam",  
  6.         LastName = "Fisher",  
  7.         Gender ="Male",  
  8.         Subjects = new List<string>() { "C-Sharp""ASP.NET""XAML" }  
  9.     };  
  10.   
  11.     //student object two  
  12.     Student studentTwo = new Student {  
  13.         StudentId = 205,  
  14.         FirstName = "Max",  
  15.         LastName = "Payne",  
  16.         Gender ="Male",  
  17.         Subjects = new List<string>() { "PHP""Java" }  
  18.     };  
  19.   
  20.     //student object three  
  21.     Student studentThree = new Student {  
  22.         StudentId = 210,  
  23.         FirstName = "Lara",  
  24.         LastName = "Croft",  
  25.         Gender ="Female",  
  26.         Subjects = new List<string>() { "PHP""C-Sharp""Phython""Java" }  
  27.     };  
  28.   
  29.     //student object four  
  30.     Student studentFour = new Student {  
  31.         StudentId = 250,  
  32.         FirstName = "Aiden",  
  33.         LastName = "Pearce",  
  34.         Gender ="Male",  
  35.         Subjects = new List<string>() { "C++" }  
  36.     };  

In the same main method, we will create a new list collection object of type student and add these four student objects.

main method

Demo 1

Let's say we want to display all the subjects that students have opted for.

subjects

If you hover your mouse on s.Subjects you will get the intellisense as in the following:

intellisense

It is a collection of List<string> and in our main method there are four student objects, meaning there will be four different IEnumerable of strings. But what this SelectMany is doing forming a single IEnumerable of string.

Run the application.

Run the application

Demo 2

Let's see what happens if we try to do the same thing using a Select operator.

Select operator

Look at the return type of the Select function, it is returning IEnumerable<List<string>> meaning a collection inside a collection.

To retrieve the subjects from this collection of collections, we can create a nested foreach loop.

retrieve the subjects

The first loop will give us a List<string> and the second loop will give us a string back.

Run the application.

string

Demo 2

Let's say with the subjects we also want the FirstName and LastName to be displayed as FullName and with that we also want to display the Id and for that we can use the third overloaded version of this SelectMany function.

SelectMany function

The first parameter expects an object of student and an expression of IEnumerable<TCollection>, in other words like a list of list collections.

The second parameter expects an object of type Student and an object of TCollection that is nothing but the type of collection we are dealing with and here the collection type is string.

TCollection

The first parameter will give us the list of all subjects, in other words we will get four List objects.

The second parameter has two objects, one of type student that will give us the Id and Name of the students and another is of type string. The list of string that we got in the first parameter will be passed as a string value here that will give us the subjects and we are assigning it to a new anonymous type.

Now all we need to do is loop through each item present in the anonymous type.

anonymous

Run the application.

anonymous type


Similar Articles