In this article, we are going to learn about Sorting and Filtering with LINQ. The Language-Integrated Query (LINQ) provides a robust set of language extensions that we can use to shape query results according to our current needs. LINQ not only allows for a type-safe way to retrieve data but also a means to sort or filter that queried data in the same way.
If unfamiliar with LINQ, or need a refresher on its many advantages or disadvantages, please read our LINQ Basic Concepts article.
Let’s see how we can use LINQ to get exactly the data we want!
How Do We Sort in LINQ?
First off, what do we mean by sorting? Sorting allows us to be able to order the elements in a set of data by one or more specific attributes. Additionally, we can of course nest the sorting to order each element in the set by whatever priority we desire.
For our sorting examples we will be using the list of custom shape objects:
var shapeList = new List<Shape>() { new Shape() { ShapeId = 0, ShapeType = "Square", ShapeHeight = 2, ShapeWidth = 2,Is3D = false }, new Shape() { ShapeId = 1, ShapeType = "Cone", ShapeHeight = 3, ShapeWidth = 1,Is3D = true }, new Shape() { ShapeId = 2, ShapeType = "Rectangle", ShapeHeight = 4, ShapeWidth = 6,Is3D = false } };
LINQ Sorting Operators
To sort this data we will use one of LINQ’s five sorting operators.
OrderBy
The OrderBy
operator sorts the data in ascending (beginning with the smallest and ending with the largest) order.
We begin by passing a lambda expression to the Orderby
method:
var sortedList = shapeList.OrderBy(sl => sl.ShapeType).ToList();
The lambda expression represents each iteration through the collection and what property of the item we wish to sort by.
Notice that the method itself does not modify the original collection. Also, because this method is an extension of the IEnumerable
type, we need to cast the IEnumerable
result to a List
to get a new List
with the data ordered as we want.
OrderByDescending
To accomplish the same but in descending order, we can use the OrderByDescending
method:Â
var sortedList = shapeList.OrderByDescending(sl => sl.ShapeId).ToList();
Notice that for sake of example, we used a different property to order by this time.
We can inspect our results after we order them by ShapeType
ascending and ShapeId
descending respectively:
---------------------------------------- ShapeId: 1 ShapeType: Cone ShapeWidth: 1 ShapeHeight: 3 is3D: True ShapeId: 2 ShapeType: Rectangle ShapeWidth: 6 ShapeHeight: 4 is3D: False ShapeId: 0 ShapeType: Square ShapeWidth: 2 ShapeHeight: 2 is3D: False ---------------------------------------- ---------------------------------------- ShapeId: 2 ShapeType: Rectangle ShapeWidth: 6 ShapeHeight: 4 is3D: False ShapeId: 1 ShapeType: Cone ShapeWidth: 1 ShapeHeight: 3 is3D: True ShapeId: 0 ShapeType: Square ShapeWidth: 2 ShapeHeight: 2 is3D: False ----------------------------------------
ThenBy
We can use the ThenBy
method after the OrderBy
method for nested sorting. After the OrderBy
method has ordered the data, we specify another property for the ThenBy
method to use.
Like in the previous examples, we have to pass a lambda expression to ThenBy
:Â
var sortedList = shapeList.OrderBy(sl => sl.Is3D).ThenBy(sl => sl.ShapeId).ToList();
In this instance, we first want to order the list by whether or not the shapes are 3D, and then we want to sort by the shapes’ id number.
ThenByDescending
We will do the same with the ThenByDescending
method:Â
var sortedList = shapeList.OrderByDescending(sl => sl.Is3D).ThenByDescending(sl => sl.ShapeId).ToList();
By using the ThenByDescending
method, we sort the second set of results in descending order.
Reverse
Reverse
is the sorting method that does not modify the original collection of items:
private static IEnumerable<Shape> LINQSortReverse(IEnumerable<Shape> shapeList) { var reversedList = shapeList.Reverse(); return reversedList; }
After we call the LINQ’s extension Reverse
method, from the Enumerable
class, it will return a reversed list while leaving the main list untouched.
How Do We Filter in LINQ?
Filtering extracts elements from the dataset based on whatever criteria we specify.
LINQ Filtering Operators
LINQ accomplishes filtering with two filtering operators.
Where
The Where
method is a powerful extension that allows us to filter the collection based on the criteria we specify: Â
var filteredList = shapeList.Where(sl => sl.ShapeHeight < 4).ToList();
In this specific example, we extract all the shapes from the list that are less than four.
If we need to filter by more than one criteria, we can utilize the logical &&
or ||
operators. However, if this becomes too verbose, we can move the expression we pass to Where
to a separate method for better readability:Â
var filteredList = shapeList.Where(sl => CheckShape(sl)).ToList();
That said, let’s check the CheckShape
method implementation:
private static bool CheckShape(Shape s) { if(s.ShapeWidth < 3 && s.Is3D) { return true; } return false; }
This method must return a bool
to properly be handled by the Where
clause.
OfType
OfType
is a unique extension method that checks to see if the current element can be cast to a specified type, if not, then the element is removed.
Accordingly, this can be useful to make certain that all the elements in this collection are our custom Shape
object: Â
var filteredList = shapeList.OfType<Shape>().ToList();
The resulting list will now only contain Shape
objects. This is extremely useful in situations where we want to use a generic collection of objects or inheritance.
Using Extension Methods
Custom static methods – extension methods – allow us to customize or add functionality to how we sort or filter the results of a LINQ query.
Let’s create an extension method to filter by removing null items from a List
collection:
public static List<T> RemoveNullFilter<T>(this List<T> list) { foreach (T item in list.ToList()) { if(item == null) { list.Remove(item); } } return list; }
The method iterates through every item in the copy of the list, removing those that are null in the original one and returning the modified list.Â
To learn more about removing elements from a list in an iteration, and why we use ToList
inside the foreach loop, feel free to read our How to Remove Elements From a Generic List in Iteration With C# article.
We call this in the same way that we called the Reverse
method:Â
shapeList.RemoveNullFilter();
Conclusion
In this article, we covered a few of the excellent ways to implement Sorting and Filtering with LINQ. We hope that using this information you will be able to be sorting and filtering your data with LINQ to get exactly what you need out of each query!