C# LINQ Filtering Operators

As was shown in the LINQ introduction, both query and method syntax provide a means of filtering data using the 'where' operator. Method syntax provides a number of other methods, which can be used to filter data. These are outlined in the table below.

Method Description
Where Returns a subset of elements that satisfy a given condition.
Take Returns the first x elements and discards the rest.
Skip Ignores the first x elements and returns the rest.
TakeWhile Emits elements from the input sequence until the given predicate is true.
SkipWhile Ignores elements from the input sequence until the given predicate is true and then emits the rest.
Distinct Returns a collection that excludes duplicates.

Below are some examples of each of the additional methods that can be used for filtering data.

class Program
{

    static void Main(string[] args)
    {

        // List containing person objects.
        List<Person> people = new List<Person>()
        {
            { new Person(1, "Bob", "Smith", "Mr", new DateTime(1980, 01, 20)) },
            { new Person(3, "Fred", "Bloggs", "Mr", new DateTime(1975, 05, 07)) },
            { new Person(4, "Alan", "White", "Mr", new DateTime(1989, 03, 20)) },
            { new Person(5, "Fiona", "Bloggs", "Mrs", new DateTime(1985, 05, 19)) },
            { new Person(6, "Zoe", "Davis", "Miss", new DateTime(1979, 07, 11)) },
            { new Person(7, "Tom", "Ingram", "Mr", new DateTime(1971, 10, 04)) },
            { new Person(8, "Karen", "Thomas", "Mrs", new DateTime(1969, 03, 08)) },
            { new Person(9, "Samantha", "Yates", "Miss", new DateTime(1995, 08, 27)) },
            { new Person(1, "Bob", "Smith", "Mr", new DateTime(1980, 01, 20)) }
        };

        Console.WriteLine("LINQ Take method:");
        Console.WriteLine();

        // LINQ Take method returns the top five elements.
        var listTakeMS = people.Take(5).ToList();

        // Display information relating to people that match the criteria.
        DisplayPeople(listTakeMS);

        Console.WriteLine();
        Console.WriteLine("LINQ Skip method:");
        Console.WriteLine();

        // LINQ Skip method ignores the first five elements.
        var listSkipMS = people.Skip(5).ToList();

        // Display information relating to people that match the criteria.
        DisplayPeople(listSkipMS);

        Console.WriteLine();
        Console.WriteLine("LINQ TakeWhile method:");
        Console.WriteLine();

        // LINQ TakeWhile method returns elements whilst the id
        // is less than or equal to 5.
        var listTakeWhileMS = people.TakeWhile(p => p.id <= 5).ToList();

        // Display information relating to people that match the criteria.
        DisplayPeople(listTakeWhileMS);

        Console.WriteLine();
        Console.WriteLine("LINQ SkipWhile method:");
        Console.WriteLine();

        // LINQ SkipWhile method skips elements where the id is
        // less than or equal to 5.
        var listSkipWhileMS = people.SkipWhile(p => p.id <= 5).ToList();

        // Display information relating to people that match the criteria.
        DisplayPeople(listSkipWhileMS);

        Console.WriteLine();
        Console.WriteLine("LINQ Distinct method:");
        Console.WriteLine();

        // LINQ Distinct method returns distinct elements.
        var listDistinctMS = people.Distinct().ToList();

        // Display information relating to people that match the criteria.
        DisplayPeople(listDistinctMS);

        Console.WriteLine();
        Console.WriteLine("LINQ Distinct method, simple list:");
        Console.WriteLine();

        // List of numbers.
        List<int> numbers = new List<int>() { 1, 2, 3, 4, 5, 1 };

        // LINQ Distinct method returns unique elements.
        var listDistinctNumbersMS = numbers.Distinct();

        // Display the distinct numbers.
        foreach (var number in listDistinctNumbersMS)
        {

            // Display the number.
            Console.WriteLine(number);

        }


    }

    // Method to display a list of 'Person' objects.
    private static void DisplayPeople(List<Person> people)
    {

        foreach (Person person in people)
        {

            // Variable to construct person details to display.
            string personDetails = "";

            // Construct the person information for display.
            personDetails += person.id + ") ";
            personDetails += person.firstName + " " + person.lastName;
            personDetails += " - Age: " + person.CalculateAge();
            personDetails += " (" + person.dob.Day.ToString().PadLeft(2, '0') + "/";
            personDetails += person.dob.Month.ToString().PadLeft(2, '0') + "/";
            personDetails += person.dob.Year + ")";

            // Display the constructed person information.
            Console.WriteLine(personDetails);

        }

    }

}

class Person
{

    public int id;
    public string firstName;
    public string lastName;
    public string title;
    public DateTime dob;

    // Constructor.
    public Person(int pId, string pFirsName, string pLastName, string pTitle, DateTime pDob)
    {

        id = pId;
        firstName = pFirsName;
        lastName = pLastName;
        title = pTitle;
        dob = pDob;

    }

    // Method to calculate a person's age.
    public int CalculateAge()
    {

        // Get the current date.
        DateTime dateToday = DateTime.Today;

        // Calculate the age.
        int currentAge = dateToday.Year - dob.Year;

        if (dob.Month > dateToday.Month ||
            (dob.Month == dateToday.Month && dob.Day > dateToday.Day))
        {
            currentAge -= 1;
        }

        return currentAge;

    }

}

Here is the output in the console from these examples.

LINQ Take method:

1) Bob Smith - Age: 41 (20/01/1980)
3) Fred Bloggs - Age: 46 (07/05/1975)
4) Alan White - Age: 32 (20/03/1989)
5) Fiona Bloggs - Age: 36 (19/05/1985)
6) Zoe Davis - Age: 41 (11/07/1979)

LINQ Skip method:

7) Tom Ingram - Age: 49 (04/10/1971)
8) Karen Thomas - Age: 52 (08/03/1969)
9) Samantha Yates - Age: 25 (27/08/1995)
1) Bob Smith - Age: 41 (20/01/1980)

LINQ TakeWhile method:

1) Bob Smith - Age: 41 (20/01/1980)
3) Fred Bloggs - Age: 46 (07/05/1975)
4) Alan White - Age: 32 (20/03/1989)
5) Fiona Bloggs - Age: 36 (19/05/1985)

LINQ SkipWhile method:

6) Zoe Davis - Age: 41 (11/07/1979)
7) Tom Ingram - Age: 49 (04/10/1971)
8) Karen Thomas - Age: 52 (08/03/1969)
9) Samantha Yates - Age: 25 (27/08/1995)
1) Bob Smith - Age: 41 (20/01/1980)

LINQ Distinct method:

1) Bob Smith - Age: 41 (20/01/1980)
3) Fred Bloggs - Age: 46 (07/05/1975)
4) Alan White - Age: 32 (20/03/1989)
5) Fiona Bloggs - Age: 36 (19/05/1985)
6) Zoe Davis - Age: 41 (11/07/1979)
7) Tom Ingram - Age: 49 (04/10/1971)
8) Karen Thomas - Age: 52 (08/03/1969)
9) Samantha Yates - Age: 25 (27/08/1995)
1) Bob Smith - Age: 41 (20/01/1980)

LINQ Distinct method, simple list:

1
2
3
4
5

There are a few things to note with the output from these methods. Firstly with 'TakeWhile', it stops when it reaches the first element with an 'id' greater than five, event though there is an element at the end with an id that is less than or equal to five. Similarly with 'SkipWhile', it includes all elements after the first one it encounters that is greater than five, event though the last element has an 'id', which is less. For the 'Distinct' method, where objects are concerned, even if the data is the same, they are two separate instances of the object, which is why they are both still included. The 'Distinct' method eliminates duplicates where, for example, a simple list of numbers is used, as in the last example.