Там какой-либо путь состоит в том, чтобы инвертировать Предикат?

Я хочу сделать что-то вроде этого:

List<SomeClass> list1 = ...
List<SomeClass> list2 = ...
Predicate<SomeClass> condition = ...

...

list2.RemoveAll (!condition);

...

list2.AddRange (list1.FindAll (condition));

Однако это приводит к ошибке компилятора, как ! не может относиться Predicate<SomeClass>. Там какой-либо путь состоит в том, чтобы сделать это?

24
задан Matthew 13 February 2010 в 15:45
поделиться

2 ответа

Вы можете использовать выражение лямбда для определения анонимного делегата Iflace, который является результатом отрицания результата предиката:

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

Другой вариант:

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

Использование:

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

Причина, по которой List.removeall (! Состояние) не работает, так это то, что нет ! Оператор, определенный на делегатах. Вот почему вы должны определить новый делегат с точки зрения условия , как показано выше.

32
ответ дан 28 November 2019 в 23:37
поделиться

Это на самом деле возможно, но, возможно, в немного другой форме, чем вы привыкли. В .NET, лямбда выражения либо можно интерпретировать как делегаты , либо в виде деревьев экспрессии . Это относительно просто выполнить не операцию на дереве выражения.

Вот образец с использованием вашего кода в качестве отправной точки:

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));
        }
    }
}
9
ответ дан 28 November 2019 в 23:37
поделиться
Другие вопросы по тегам:

Похожие вопросы: