In this article we show how to use predicates in C#. With predicates, we can create code that is more clean and readable.
in general meaning is a statement about something that is either true or false. In programming, predicates represent single argument functions that return a boolean value.
Predicates in C# are implemented with delegates. The Predicate delegate represents the method that defines a set of criteria and determines whether the specified object meets those criteria.
The following example creates a simple C# Predicate.
List data = [1, -2, 3, 0, 2, -1]; var predicate = new Predicate(isPositive); var filtered = data.FindAll(predicate); Console.WriteLine(string.Join(",", filtered)); bool isPositive(int val) < return val >0; >
In the example, the predicate is used to filter out positive values.
var predicate = new Predicate(IsPositive);
A predicate delegate is defined; it takes the IsPositive method as parameter.
var filtered = data.FindAll(predicate);
We pass the predicate to the FindAll method of a list, which retrieves all values for which the predicate returns true.
bool IsPositive(int val) < return val >0; >
The IsPositive returs true for all values greater than zero.
$ dotnet run 1,3,2
The following example passes an anonymous method to the delegate.
List data = [1, -2, 3, 0, 2, -1]; Predicate isPositive = delegate(int val) < return val >0; >; var filtered = data.FindAll(isPositive); Console.WriteLine(string.Join(",", filtered));
The example uses the delegate keyword to define an anonymous method.
C# lambda expression simplifies the creation of C# Predicates. Lambda expressions are created with the => lambda declaration operator.
List words = [ "falcon", "wood", "tree", "rock", "cloud", "rain" ]; Predicate hasFourChars = word => word.Length == 4; var words2 = words.FindAll(hasFourChars); Console.WriteLine(string.Join(',', words2));
In the example, we find out all words that have four letters.
$ dotnet run wood,tree,rock,rain
The Exists method of a list determines whether the list contains elements that match the conditions defined by the specified predicate.
List words = [ "sky", "", "club", "spy", "silk", "summer", "war", "cup", "cloud", "coin", "small", "terse", "", "snow", "snail", "see"]; Predicate pred = string.IsNullOrEmpty; if (words.Exists(pred)) < Console.WriteLine("There is an empty string"); >elseWe check if there are some empty strings in the list.
$ dotnet run There is an empty string
The RemoveAll method of a list removes all the elements that match the conditions defined by the specified predicate.
List words = ["sky", "town", "club", "spy", "silk", "snail", "war", "cup", "cloud", "coin", "small", "terse"]; Predicate HasThreeChars = word => word.Length == 3; words.RemoveAll(HasThreeChars); Console.WriteLine(string.Join(", ", words));
We have a list of words. We remove all words which have three latin characters.
$ dotnet run town, club, silk, snail, cloud, coin, small, terse
The next example uses a predicate with two conditions.
List countries = [ new ("Iran", 80840713), new ("Hungary", 9845000), new ("Poland", 38485000), new ("India", 1342512000), new ("Latvia", 1978000), new ("Vietnam", 95261000), new ("Sweden", 9967000), new ("Iceland", 337600), new ("Israel", 8622000) ]; Predicate p1 = c => c.Name.StartsWith('I'); Predicate p2 = c => c.Population > 1000_0000; Predicate CombineAnd = c => p1(c) && p2(c); var result = countries.FindAll(CombineAnd); Console.WriteLine(string.Join(", ", result)); record Country(string Name, int Population);
We create a list of countries. We find all countries that start with 'I' and have population over one million.
Predicate p1 = c => c.Name.StartsWith('I'); Predicate p2 = c => c.Population > 1000_0000;
We define two predicates.
Predicate CombineAnd = c => p1(c) && p2(c);
We combine the two predicates.
var result = countries.FindAll(CombineAnd);
We apply the combined predicate to the FindAll method.
$ dotnet run Country < Name = Iran, Population = 80840713 >, Country < Name = India, .
We can create a delegate that negates an already defined delegate.
List words = [ "falcon", "wood", "tree", "rock", "cloud", "rain" ]; Predicate HasFourChars = word => word.Length == 4; Predicate Negate = word => !HasFourChars(word); var words2 = words.FindAll(Negate); Console.WriteLine(string.Join(',', words2)); // Predicate Negate(Predicate predicate) // < // return x =>!predicate(x); // >
The example negates the HasFourChars delegate. An alternative solution is commented out.
$ dotnet run falcon,cloud
These are the words whose length is not four letters.
The Func is a generic delegate type. It can contain 0 to 16 input parameters and must have one return type. Predicate is a specialization of Func .
List data = [ new ("John Doe", "gardener"), new ("Robert Brown", "programmer"), new ("Lucia Smith", "teacher"), new ("Thomas Neuwirth", "teacher") ]; ShowOutput(data, r => r.Occupation == "teacher"); void ShowOutput(List list, Func condition) < var data = list.Where(condition); foreach (var person in data) < Console.WriteLine($", "); > > record Person(string Name, string Occupation);
The example creates a list of persons. The ShowOutput method takes a predicate as the second parameter. It returns all persons who are teachers.
The Array.FindAll method retrieves all the elements that match the conditions defined by the specified predicate.
User[] users = [ new (1, "John", "London", "2001-04-01"), new (2, "Lenny", "New York", "1997-12-11"), new (3, "Andrew", "Boston", "1987-02-22"), new (4, "Peter", "Prague", "1936-03-24"), new (5, "Anna", "Bratislava", "1973-11-18"), new (6, "Albert", "Bratislava", "1940-12-11"), new (7, "Adam", "Trnava", "1983-12-01"), new (8, "Robert", "Bratislava", "1935-05-15"), new (9, "Robert", "Prague", "1998-03-14"), ]; var age = 60; Predicate olderThan = e => GetAge(e) > age; var res = Array.FindAll(users, olderThan); foreach (var e in res) < Console.WriteLine(e); >int GetAge(User user) < var dob = DateTime.Parse(user.DateOfBirth); return (int) Math.Floor((DateTime.Now - dob).TotalDays / 365.25D); >record User(int Id, string Name, string City, string DateOfBirth);
We get all users that are older than 60.
Predicate olderThan = e => GetAge(e) > age;
In the predicate definition, we uset the GetAge method to determine the age of the user.
var res = Array.FindAll(users, olderThan);
The Array.FindAll method retrieves all the elements that match the conditions defined by the specified predicate.
int GetAge(User user) < var dob = DateTime.Parse(user.DateOfBirth); return (int) Math.Floor((DateTime.Now - dob).TotalDays / 365.25D); >
The GetAge method parses the date of birth string and computes the current age.
$ dotnet run User < Name = Peter, City = Prague, DateOfBirth = 1936-03-24 >User < Name = Albert, City = Bratislava, DateOfBirth = 1940-12-11 >UserNext, we define a FindAll list extension method.
ExtensionMethodspublic static class ExtensionMethods < public static ListFindAll(this List vals, Listpreds) < Listdata = new List(); foreach (T e in vals) < bool pass = true; foreach (Predicatep in preds) < if (!(p(e))) < pass = false; break; >> if (pass) data.Add(e); > return data; > >
The FindAll method returns list elements that fill all the specified predicates.
public static List FindAll(this List vals, Listpreds)
The FindAll method takes a list of generic predicate functions as a parameter. It returns a filtered generic list.
List> preds = [e => e > 0, e => e % 2 == 0]; List vals = [-3, -2, -1, 0, 1, 2, 3, 4]; var filtered = vals.FindAll(preds); foreach (var e in filtered) < Console.WriteLine(e); >Console.WriteLine("---------------------"); List words = ["sky", "wrath", "wet", "sun", "pick", "who", "cloud", "war", "water", "jump", "ocean"]; ListWe define two lists: an integer list and a string list. From the integer list, we filter out all positive even values. From the string list, we get all words that start with 'w' and have three letters.
$ dotnet run 2 4 --------------------- wet who war
In this article we have worked with C# Predicate .
My name is Jan Bodnar and I am a passionate programmer with many years of programming experience. I have been writing programming articles since 2007. So far, I have written over 1400 articles and 8 e-books. I have over eight years of experience in teaching programming.