ZetCode

C# Predicate

last modified July 5, 2023

C# Predicate tutorial shows how to use predicates in C#. With predicates, we can create code that is more clean and readable.

Predicate

Predicate 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.

C# Predicate

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.

C# Predicate example

The following example creates a simple C# Predicate.

Program.cs
var data = new List<int> { 1, -2, 3, 0, 2, -1 };

var predicate = new Predicate<int>(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<int>(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

C# Predicate with anonymous method

The following example passes an anonymous method to the delegate.

Program.cs
var data = new List<int> { 1, -2, 3, 0, 2, -1 };

Predicate<int> 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# Predicate with lambda expression

C# lambda expression simplifies the creation of C# Predicates. Lambda expressions are created with the => lambda declaration operator.

Program.cs
var words = new List<string> { "falcon", "wood", "tree",
    "rock", "cloud", "rain" };

Predicate<string> 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

C# Predicate with Exists

The Exists method of a list determines whether the list contains elements that match the conditions defined by the specified predicate.

Program.cs
var words = new List<string> { "sky", "", "club", "spy", "silk", "summer",
        "war", "cup", "cloud", "coin", "small", "terse", "",
        "snow", "snail", "see"};

Predicate<string> pred = String.IsNullOrEmpty;

if (words.Exists(pred))
{
    Console.WriteLine("There is an empty string");
}
else
{
    Console.WriteLine("There is no empty string");
}

We check if there are some empty strings in the list.

$ dotnet run 
There is an empty string

C# Predicate with RemoveAll

The RemoveAll method of a list removes all the elements that match the conditions defined by the specified predicate.

Program.cs
var words = new List<string> { "sky", "town", "club", "spy", "silk", "snail",
        "war", "cup", "cloud", "coin", "small", "terse"};

Predicate<string> 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

C# Predicate multiple conditions

The next example uses a predicate with two conditions.

Program.cs
var countries = new List<Country>
{
    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<Country> p1 = c => c.Name.StartsWith("I");
Predicate<Country> p2 = c => c.Population > 1000_0000;

Predicate<Country> 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<Country> p1 = c => c.Name.StartsWith("I");
Predicate<Country> p2 = c => c.Population > 1000_0000;

We define two predicates.

Predicate<Country> 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, ...

C# negating predicates

We can create a delegate that negates an already defined delegate.

Program.cs
var words = new List<string> { "falcon", "wood", "tree",
    "rock", "cloud", "rain" };

Predicate<string> HasFourChars = word => word.Length == 4;
Predicate<string> Negate = word => !HasFourChars(word);

var words2 = words.FindAll(Negate);

Console.WriteLine(string.Join(',', words2));


// Predicate<T> Negate<T>(Predicate<T> 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.

C# predicate with Func

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.

Program.cs
var data = new List<Person>
{
    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<Person> list, Func<Person, bool> condition)
{
    var data = list.Where(condition);

    foreach (var person in data)
    {
        Console.WriteLine($"{person.Name}, {person.Occupation}");
    }
}

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.

C# Predicate with Array.FindAll

The Array.FindAll method retrieves all the elements that match the conditions defined by the specified predicate.

Program.cs
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<User> 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<User> 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 { id = 4, Name = Peter, City = Prague, DateOfBirth = 1936-03-24 }
User { id = 6, Name = Albert, City = Bratislava, DateOfBirth = 1940-12-11 }
User { id = 8, Name = Robert, City = Bratislava, DateOfBirth = 1935-05-15 }

C# generic FindAll

Next, we define a FindAll list extension method.

ExtensionMethods
public static class ExtensionMethods
{
    public static List<T> FindAll<T>(this List<T> vals, List<Predicate<T>> preds)
    {
        List<T> data = new List<T>();

        foreach (T e in vals)
        {
            bool pass = true;

            foreach (Predicate<T> p 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<T> FindAll<T>(this List<T> vals, List<Predicate<T>> preds)

The FindAll method takes a list of generic predicate functions as a parameter. It returns a filtered generic list.

Program.cs
var preds = new List<Predicate<int>>();
preds.Add(e => e > 0);
preds.Add(e => e % 2 == 0);

var vals = new List<int> {-3, -2, -1, 0, 1, 2, 3, 4};
var filtered = vals.FindAll(preds);

foreach (var e in filtered) {

    Console.WriteLine(e);
}

Console.WriteLine("---------------------");

var words = new List<string> {"sky", "wrath", "wet", "sun", "pick", "who", 
    "cloud", "war", "water", "jump", "ocean"};

var preds2 = new List<Predicate<string>>();
preds2.Add(e => e.StartsWith("w"));
preds2.Add(e => e.Length == 3);

var filtered2 = words.FindAll(preds2);

foreach (var e in filtered2) {

    Console.WriteLine(e);
}

We 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.

Author

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.

List all C# tutorials.