Is there any way in c# .NET 2.0! to combine multiple Predicates?
Let's say I have the following code.
List<string> names = new List<string>(); names.Add("Jacob"); names.Add("Emma"); names.Add("Michael"); names.Add("Isabella"); names.Add("Ethan"); names.Add("Emily"); List<string> filteredNames = names.FindAll(StartsWithE); static bool StartsWithE(string s) { if (s.StartsWith("E")) { return true; } else { return false; } }
This gives me:
Emma Ethan Emily
So this is pretty cool stuff, but I know want to be able to filter using multiple predicates.
So I want to be able to say something like this:
List<string> filteredNames = names.FindAll(StartsWithE OR StartsWithI);
In order to get:
Emma Isabella Ethan Emily
How can I achieve this? Currently I am just filtering the complete list twice and combining the results afterwards. But unfortunately this is quite inefficent and even more importantly I lose the original sort order, which is not acceptable in my situation.
I also need to be able to iterate over any number of filters/predicates as there can be quite a lot.
Again it needs to be a .NET 2.0 solution unfortunately I can't use a newer version of the framework
Thanks a lot.
When two sentences have the same subject, we can combine their predicates using a special word called a conjunction. Conjunctions are words like 'and', 'but', and 'so'. They combine sentences or parts of sentences. To combine predicates, we use the conjunction 'and'.
The Predicate or() method is used to combine a Predicate instance with another, to compose a third Predicate instance. The composed Predicate will return true if either of the Predicate instances it is composed from return true , when their test() methods are called with same input parameter as the composed 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.
How about:
public static Predicate<T> Or<T>(params Predicate<T>[] predicates) { return delegate (T item) { foreach (Predicate<T> predicate in predicates) { if (predicate(item)) { return true; } } return false; }; }
And for completeness:
public static Predicate<T> And<T>(params Predicate<T>[] predicates) { return delegate (T item) { foreach (Predicate<T> predicate in predicates) { if (!predicate(item)) { return false; } } return true; }; }
Then call it with:
List<string> filteredNames = names.FindAll(Helpers.Or(StartsWithE, StartsWithI));
Another alternative would be to use multicast delegates and then split them using GetInvocationList()
, then do the same thing. Then you could do:
List<string> filteredNames = names.FindAll(Helpers.Or(StartsWithE+StartsWithI));
I'm not a huge fan of the latter approach though - it feels like a bit of an abuse of multicasting.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With