Skip to content

LINQ and Lambdas#

Lambdas#

Lambda expressions are just another way to write methods.

static bool SomePredicate(Point p)
{
    return p.X * p.Y> 100000;
}
Predicate<Point> d = SomePredicate;

Predicate<Point> d = delegate(Point p)
{
    return p.X*p.Y> 100000;
};

Predicate<Point> d = p => p.X* p.Y> 100000;

Closures#

A lambda expression may use variables defined outside its context («outer variables»). here factor

void doSomething()
{
    var factor = 2;
    Func<int, int> multiplier= n => n * factor;
    Console.WriteLine(multiplier(3)); //6
}
Be careful!! Writes the current value of i and not the value of i back when the delegate was created.
var actions = newList<Action>();
for(var i = 0; i < 10; i++)
    actions.Add(() => Console.WriteLine(i));
foreach(var action in actions)
    action(); // 101010101010101...
The solution to this is to declare a new “inner variable" for each iteration to be captured, instead of a single “outer variable" which is captured only once.
for(var i = 0; i < 10; i++)
{
    varj = i; //each iteration gets its own,new variable j
    actions.Add(() => Console.WriteLine(j));
}

LINQ#

LINQ = Language INtegrted Query are just like streams in Java. LINQ features can be used in a C# program by importing the System.Linq namespace.

LINQ is executed when results are accessed, not when the query is created. Execution happens when: - iterating over results - calling immediate execution methods like toList, Count etc.

NEVER modifystate using LINQ!!!

ForEach is NOT LINQ

persons.ForEach(p => Console.WriteLine(p.FirstName));

Method & Query Syntax#

Method syntax resembles most other C# method calls, while query syntax resembles SQL. Query must begin with from clause, and end with select or group clause Between first from clause and last select/group clause, it can contain one or more of the following clauses:Where, Orderby, Join, Let, From, Into

// Method syntax  
var custQuery2 = customers.Where(c => c.City == "London"); 
var orderedByLength = names.OrderBy(n => n.Length);

// Query syntax  
var custQuery =   
    FROM c IN customers   
    WHERE c.City == "London"   
    SELECT c;
// Mix
var results = (FROM c IN Comedians SELECT c).Count();

Simple queries#

// **** AGGREGATE ****
var min = array.Min(); // All below can also be called straight on array
var count = array.Count()
var condCount = data.Count(x => x.Condition == true) 
var sumAges = persons.Sum(p => p.Age);
var minAge = persons.Min(p => p.Age); 
var minAge = persons.Max(p => p.Age); 
var avgAge = persons.Average(p => p.Age);
var simplePersons = persons.Select(p => new { Surname = p.Surname, Firstname = p.Firstname}) // creates an enumarable of anonymous class

// **** CONVERSIONS ****
data.ToArray(); // Convert to Array
data.ToList(); // Convert to List
data.ToDictionary( x=> x.Name ); // Convert to Dictionary keyed on Name
// **** ELEMENT ****

data.First() // Returns the first element
data.First( x=> x.Type == Types.A ) // Returns the first element passing the condition
data.FirstOrDefault() // Returns the first element or default
data.FirstOrDefault( x => x.Type == Types.B ) // Returns the first element passing the condition or default

data.Last() // Returns the last element
data.Last( x=> x.Type == Types.A ) // Returns the last element passing the condition
data.LastOrDefault( ) // Returns the last element or default*
data.LastOrDefault( x => x.Type == Types.B ) // Returns the last element passing the condition or default*

data.ElementAt(0) // Returns the element at position 0

// **** FILTERS ****

var even array.Where(x => x%2==0) // Returns all elements passing the condition

data.Where(( x, index) => index <= 4 && x.Type == Types.A) // The elements index can be passed into the delegate

// **** GENERATION ****
Enumerable.Range(1, 10); // Creates collection of 10 items between 1 and 10
Enumerable.Repeat(1, 10); // Creates a collection of 10 1s.

// **** ORDERING ****

data.OrderBy(x => x.Name); // Order by Name ASC
data.OrderBy(x => x.Name).ThenBy(x => x.Age); // Order by Name ASC the Age ASC
data.OrderBy(x => x.Name).ThenByDescending(x => x.Age); // Order by Name ASC then Age DESC
data.OrderByDescending (x => x.Name); // Order by Name DESC
data.OrderBy(x => x.Name).Reverse(); // Reverse elements

// **** PARTITIONING ****

data.Take (3); // Take 3 items
data.Skip (3); // Skip 3 items

data.TakeWhile (x=>x.Type ==Types.A); // Take all the items while the condition is met
data.SkipWhile (x=>x.Type ==Types.A); // Skip all the items while the condition is met

// **** PROJECTION ****

data.Select(x => x.Name); // Select collection of a column

data.Select(x => new { Name = x.Name, Age = x.Age }); // Select a collection of columns through an anonymus type

// **** QUANTIFIERS ****
if(array.Any(i=> i% 2 == 0))
if(array.All(i=> i% 2 == 0))

// **** SET ****


data.Intersect(dataTwo); // Returns the union / intersection of data; elements in both collections

data.Except(dataTwo); // Returns elements in data which are not in dataTwo

data.Concat(dataTwo); // Concatonates both collections; appends dataTwo to data

Grouping#

var users = new List<User>()    
    {    
        new User { Name = "John Doe", Age = 42, HomeCountry = "USA" },    
        new User { Name = "Jane Doe", Age = 38, HomeCountry = "USA" },    
        new User { Name = "Joe Doe", Age = 19, HomeCountry = "Germany" },    
        new User { Name = "Jenna Doe", Age = 19, HomeCountry = "Germany" },    
        new User { Name = "James Doe", Age = 8, HomeCountry = "USA" },    
    };    
var usersGroupedByCountry = users.GroupBy(user => user.HomeCountry);    
foreach(var group in usersGroupedByCountry)    
{    
    Console.WriteLine("Users from " + group.Key + ":");    
    foreach(var user in group)    
        Console.WriteLine("* " + user.Name);
}

Distinct#

students.Distinct(); // Returns a collection of distinct elements
students.Distinct (new StudentComparer()). // Distinct with providing an equality provider

public class StudentComparer : IEqualityComparer<Student>
    {
        public bool Equals(Student x, Student y)
        {
            //First check if both object reference are equal then return true
            if(object.ReferenceEquals(x, y))
            {
                return true;
            }
            //If either one of the object refernce is null, return false
            if (object.ReferenceEquals(x,null) || object.ReferenceEquals(y, null))
            {
                return false;
            }
            //Comparing all the properties one by one
            return x.ID == y.ID && x.Name == y.Name;
        }
        public int GetHashCode(Student obj)
        {
            //If obj is null then return 0
            if (obj == null)
            {
                return 0;
            }
            //Get the ID hash code value
            int IDHashCode = obj.ID.GetHashCode();
            //Get the string HashCode Value
            //Check for null refernece exception
            int NameHashCode = obj.Name == null ? 0 : obj.Name.GetHashCode();
            return IDHashCode ^ NameHashCode;
        }
    }

Join#

IList<Student> studentList = new List<Student>() { 
    new Student() { StudentID = 1, StudentName = "John", StandardID =1 },
    new Student() { StudentID = 2, StudentName = "Moin", StandardID =1 },
    new Student() { StudentID = 3, StudentName = "Bill", StandardID =2 },
    new Student() { StudentID = 4, StudentName = "Ram" , StandardID =2 },
    new Student() { StudentID = 5, StudentName = "Ron"  } 
};

IList<Standard> standardList = new List<Standard>() { 
    new Standard(){ StandardID = 1, StandardName="Standard 1"},
    new Standard(){ StandardID = 2, StandardName="Standard 2"},
    new Standard(){ StandardID = 3, StandardName="Standard 3"}
};

var innerJoin = studentList.Join(// outer sequence 
                      standardList,  // inner sequence 
                      student => student.StandardID,    // outerKeySelector
                      standard => standard.StandardID,  // innerKeySelector
                      (student, standard) => new  // result selector
                                    {
                                        StudentName = student.StudentName,
                                        StandardName = standard.StandardName
                                    });
/*
John - Standard 1  
Moin - Standard 1  
Bill - Standard 2  
Ram - Standard 2
*/

SelectMany#

SelectMany() flattens the resulting sequences into one sequence, and invokes a result selector function on each element therein.

PetOwner[] petOwners =
         { new PetOwner { Name="Higa, Sidney",
              Pets = new List<string>{ "Scruffy", "Sam" } },
           new PetOwner { Name="Ashkenazi, Ronen",
              Pets = new List<string>{ "Walker", "Sugar" } },
           new PetOwner { Name="Price, Vernette",
              Pets = new List<string>{ "Scratches", "Diesel" } } };

// Query using SelectMany().
IEnumerable<string> query1 = petOwners.SelectMany(petOwner => petOwner.Pets);

Console.WriteLine("Using SelectMany():");

// Only one foreach loop is required to iterate
// through the results since it is a
// one-dimensional collection.
foreach (string pet in query1)
{
    Console.WriteLine(pet);
}

// This code shows how to use Select()
// instead of SelectMany().
IEnumerable<List<String>> query2 =
    petOwners.Select(petOwner => petOwner.Pets);

Console.WriteLine("\nUsing Select():");

// Notice that two foreach loops are required to
// iterate through the results
// because the query returns a collection of arrays.
foreach (List<String> petList in query2)
{
    foreach (string pet in petList)
    {
        Console.WriteLine(pet);
    }
    Console.WriteLine();
}
/*
Using SelectMany():
Scruffy
Sam
Walker
Sugar
Scratches
Diesel

Using Select():
Scruffy
Sam

Walker
Sugar

Scratches
Diesel
*/

Back to top