Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there any way to negate a Predicate?

I want to do something like this:

List<SomeClass> list1 = ... List<SomeClass> list2 = ... Predicate<SomeClass> condition = ...  ...  list2.RemoveAll (!condition);  ...  list2.AddRange (list1.FindAll (condition)); 

However, this results in a compiler error, as ! can't be applied to Predicate<SomeClass>. Is there any way to do this?

like image 904
Matthew Avatar asked Jan 30 '10 02:01

Matthew


People also ask

How do you negate a predicate?

To negate a sequence of nested quantifiers, you flip each quantifier in the sequence and then negate the predicate. So the negation of ∀x ∃y : P(x, y) is ∃x ∀y : P(x, y) and So the negation of ∃x ∀y : P(x, y) and ∀x ∃y : P(x, y).

What is a negative predicate?

1 Predicate negation: negative and opposite predicates. Negation in logic is an operator reversing truth- or semantic-values. In natural language negation turns an affirmative sentence into its denial.

What is neg predicate in Java 8?

Predicate negate() Method The Predicate. negate() method returns the logical negation of an existing predicate. Predicate<Integer> isEven = i -> i % 2 == 0; Predicate<Integer> isOdd = isEven.


2 Answers

You could use a lambda expression to define an anonymous delegate inplace that is the result of negating the result of the predicate:

list.RemoveAll(x => !condition(x));     

Another option:

static Predicate<T> Negate<T>(Predicate<T> predicate) {      return x => !predicate(x); } 

Usage:

// list is List<T> some T // predicate is Predicate<T> some T list.RemoveAll(Negate(predicate)); 

The reason that list.RemoveAll(!condition) does not work is that there is no ! operator defined on delegates. This is why you must define a new delegate in terms of condition as shown above.

like image 102
jason Avatar answered Sep 22 '22 04:09

jason


This is actually possible, but maybe in a slightly different form than you're used to. In .NET, lambda expressions can either be interpreted as delegates OR as expression trees. It is relatively straightforward to perform a NOT operation on an expression tree.

Here is a sample using your code as a starting point:

namespace Sample {     using System;     using System.Collections.Generic;     using System.Linq.Expressions;      internal class ExpressionSample     {         private static Expression<TDelegate> Negate<TDelegate>(Expression<TDelegate> expression)         {             return Expression.Lambda<TDelegate>(Expression.Not(expression.Body), expression.Parameters);         }          private static void Main()         {             // Match any string of length 2 or more characters             Expression<Predicate<string>> expression = (s) => s.Length > 1;              // Logical negation, i.e. match string of length 1 or fewer characters             Expression<Predicate<string>> negatedExpression = ExpressionSample.Negate(expression);              // Compile expressions to predicates             Predicate<string> predicate = expression.Compile();             Predicate<string> negativePredicate = negatedExpression.Compile();              List<string> list1 = new List<string> { string.Empty, "an item", "x", "another item" };             List<string> list2 = new List<string> { "yet another item", "still another item", "y", string.Empty };              list2.RemoveAll(negativePredicate);             list2.AddRange(list1.FindAll(predicate));              list2.ForEach((s) => Console.WriteLine(s));         }     } } 
like image 21
bobbymcr Avatar answered Sep 21 '22 04:09

bobbymcr