Конкатенация функций лямбды в C#

Мне очень нравится решение, предложенное @Brian Diggs. Однако в моем случае я создаю линейные графики в цикле, а не предоставляю их явно, потому что я не знаю apriori, сколько графиков у меня будет. Когда я попытался адаптировать код @ Брайана, я столкнулся с некоторыми проблемами с правильной обработкой цветов. Оказалось, мне нужно было изменить эстетические функции. Если у кого-то такая же проблема, вот код, который работал для меня.

Я использовал тот же фрейм данных, что и @Brian:

data <- structure(list(month = structure(c(1317452400, 1317538800, 1317625200, 1317711600, 
                                       1317798000, 1317884400, 1317970800, 1318057200, 
                                       1318143600, 1318230000, 1318316400, 1318402800, 
                                       1318489200, 1318575600, 1318662000, 1318748400, 
                                       1318834800, 1318921200, 1319007600, 1319094000), 
                                     class = c("POSIXct", "POSIXt"), tzone = ""),
                   TempMax = c(26.58, 27.78, 27.9, 27.44, 30.9, 30.44, 27.57, 25.71, 
                               25.98, 26.84, 33.58, 30.7, 31.3, 27.18, 26.58, 26.18, 
                               25.19, 24.19, 27.65, 23.92), 
                   TempMed = c(22.88, 22.87, 22.41, 21.63, 22.43, 22.29, 21.89, 20.52,
                                 19.71, 20.73, 23.51, 23.13, 22.95, 21.95, 21.91, 20.72, 
                                 20.45, 19.42, 19.97, 19.61), 
                   TempMin = c(19.34, 19.14, 18.34, 17.49, 16.75, 16.75, 16.88, 16.82, 
                               14.82, 16.01, 16.88, 17.55, 16.75, 17.22, 19.01, 16.95, 
                               17.55, 15.21, 14.22, 16.42)), 
              .Names = c("month", "TempMax", "TempMed", "TempMin"), 
              row.names = c(NA, 20L), class = "data.frame")  

В моем случае я генерирую динамические my.cols и my.names, но я не хочу делать вещи излишне сложны, поэтому я даю их явно здесь. Эти три строки упрощают упорядочение легенды и присваивают цвета.

my.cols <- heat.colors(3, alpha=1)
my.names <- c("TempMin", "TempMed", "TempMax")
names(my.cols) <- my.names

И вот график:

p <-  ggplot(data, aes(x = month))

for (i in 1:3){
  p <- p + geom_line(aes_(y = as.name(names(data[i+1])), colour = 
colnames(data[i+1])))#as.character(my.names[i])))
}
p + scale_colour_manual("", 
                        breaks = as.character(my.names),
                        values = my.cols)
p

27
задан John Oxley 29 January 2009 в 14:25
поделиться

6 ответов

"делегат + = метод" является оператором для многоадресного делегата для объединения метода для делегирования. В другом ручном "делегате - = метод" является оператором для удаления метода от делегата. Это полезно для Действия.

Action action = Method1;
action += Method2;
action += Method3;
action -= Method2;
action();

В этом случае, только Method1 и Method3 будут работать, Method2 не будет работать, потому что Вы удаляете метод, прежде чем вызовут делегата.

при использовании многоадресного делегата с Func результатом будет последний метод.

Func<int> func = () => 1;
func += () => 2;
func += () => 3;
int result = func();

В этом случае, результат будет 3, начиная с метода" () =>, 3 дюйма являются последним методом, добавленным к делегату. Так или иначе весь метод назовут.

В Вашем случае, метод "t => t. Сумма < 100" будет эффективным.

, Если Вы хотите объединить предикат, я предлагаю эти дополнительные методы.

public static Func<T, bool> AndAlso<T>(
    this Func<T, bool> predicate1, 
    Func<T, bool> predicate2) 
{
    return arg => predicate1(arg) && predicate2(arg);
}

public static Func<T, bool> OrElse<T>(
    this Func<T, bool> predicate1, 
    Func<T, bool> predicate2) 
{
    return arg => predicate1(arg) || predicate2(arg);
}

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

public static Func<Tran, bool> GetPredicate() {
    Func<Tran, bool> predicate = null;
    predicate = t => t.Response == "00";
    predicate = predicate.AndAlso(t => t.Amount < 100);
    return predicate;
}

РЕДАКТИРОВАНИЕ: исправьте название дополнительных методов, как Keith предполагает.

33
ответ дан FishBasketGordo 14 October 2019 в 12:55
поделиться

Когда Вы используете + = или - =, когда делегат вводит, который просто звонит к Delegate.Combine и Delegate.Remove.

важная вещь о многоадресных делегатах состоит в том, что возвращаемое значение все кроме последнего выполняемого делегата проигнорированы. Они все выполняются (если исключение не выдается), но только последнее возвращаемое значение используется.

Для предикатов, Вы могли бы хотеть сделать что-то как:

public static Func<T, bool> And<T>(params Func<T, bool>[] predicates)
{
    return t => predicates.All(predicate => predicate(t));
}

public static Func<T, bool> Or<T>(params Func<T, bool>[] predicates)
{
    return t => predicates.Any(predicate => predicate(t));
}

Вы затем сделали бы:

Func<string, bool> predicate = And<string>(
    t => t.Length > 10,
    t => t.Length < 20);

РЕДАКТИРОВАНИЕ: вот более общее решение, которое довольно забавно, если немного причудливый...

public static Func<TInput, TOuput> Combine<TInput, TOutput>
    (Func<TOutput, TOutput, TOutput> aggregator,
     params Func<TInput, TOuput>[] delegates) {

    // delegates[0] provides the initial value
    return t => delegates.Skip(1).Aggregate(delegates[0](t), aggregator);
}

, Таким образом, Вы могли затем реализация И как:

public static Func<T, bool> And<T>(params Func<T, bool>[] predicates) {
    return Combine<T, bool>((x, y) => x && y, predicates);
}

(я лично предпочитаю это по использованию GetInvocationList(), потому что Вы заканчиваете с предикатом, который можно передать другим битам LINQ и т.д.)

20
ответ дан Jon Skeet 14 October 2019 в 12:55
поделиться

На самом деле это не работает. Попытайтесь протестировать его со случаем, где первое условие ПЕРЕСТАЛО РАБОТАТЬ, но вторые передачи. Вы найдете, что это возвратит true. Причина, потому что при контакте с многоадресными делегатами, которые возвращают значения, только последнее значение возвращено. Например:

        Func<string, bool> predicate = null;
        predicate += t => t.Length > 10;
        predicate += t => t.Length < 20;

        bool b = predicate("12345");

Это возвратит TRUE, потому что последний вызов функции возвращает true (это - меньше чем 20). Чтобы действительно заставить его работать, необходимо звонить:

predicate.GetInvocationList();

, который возвращает массив делегатов. Затем необходимо удостовериться, что они ВСЕ возвращают true для конечного результата быть верными. Иметь смысл?

13
ответ дан BFree 14 October 2019 в 12:55
поделиться

Подробно останавливаясь на ответе BFREE (+1'd это)

, Если Вы хотите получить поведение, которое Вы ищете, необходимо будет явно объединить предикаты в цепочку вместе. Вот пример

public static Func<Tran, bool> GetPredicate()
{
    Func<Tran, bool> predicate1 = t => t.Response == "00";
    Func<Tran, bool> predicate2 = t => t.Amount < 100;
    return t => predicate1(t) && predicate2(t);
}
6
ответ дан JaredPar 14 October 2019 в 12:55
поделиться

Если Вы хотите объединить предикаты, попробуйте это;

public static Predicate<T> Combine<T>(params Predicate<T>[] predicates)
{
return t => predicates.All(pr => pr(t));
}

Вы называете его как это;

Predicate<string> shortAndSweet = Combine<string>
(
    s => s.Length < 10,  // short,
    s => s == "sweet"    // and sweet
);
1
ответ дан Steve Cooper 14 October 2019 в 12:55
поделиться

+ = синтаксический сахар, конкретно реализованный для поддержки добавляющих обработчиков к событиям. Так как события являются просто особым случаем делегата, и Func является также делегатом, синтаксис появляется для работы здесь.

, Но действительно ли Вы уверены, что это работает как ожидалось? Этим я имею в виду, Вы ожидаете И или ИЛИ оценка? Как Вы реализовали бы противоположное, если бы Вы хотели его? Вы уверены, что это только возвращает результат первого? Или последнее?

0
ответ дан Joel Coehoorn 14 October 2019 в 12:55
поделиться
Другие вопросы по тегам:

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