Рекурсивно выполнять функции в списке - PullRequest
2 голосов
/ 14 ноября 2010

Имея список Func<string, string>, можно ли написать оператор, который перебирает список и возвращает результат примерно так:

string result = f1(f2(f..(input));

У меня есть следующий код (который работает), ноЯ не удовлетворен временной переменной.

public static string WrapEachElementWith<T>
    (   this IEnumerable<T> target, 
        params Func<string, string>[] func )
{
    string result = string.Empty;
    target.Each(s =>
                    {
                        var tmp = s.ToString();
                        func.Reverse().Each(x => tmp = x(tmp));
                        result += tmp;
                    });
    return result;
}

Как упростить / рефакторинг?

ОБНОВЛЕНИЕ: Я должен был предоставить больше информации.Я играю с функциональным программированием на c # после просмотра сеанса JavaScript более высокого порядка и оскорбительного сеанса Джона c # в Oredev.

Цель - создать html.

var TABLE = WrapWith("TABLE");
var TR = WrapWith("TR");
var TD = WrapWith("TD");
const string expected = "<TABLE><TR><TD>1</TD></TR><TR><TD>2</TD></TR></TABLE>";

var result = TABLE(stringArray.WrapEachWith(TR, TD));
result.ShouldEqual(expected);

static Func<String, String> WrapWith(string element)
{
    var startTag = '<' + element + '>';
    var endTag = "</" + element + '>';
    return s => startTag + s + endTag;
}

Ответы [ 3 ]

3 голосов
/ 14 ноября 2010

Мне кажется, ты делаешь четыре вещи:

  • Преобразование каждого элемента в строку
  • Применение функций по очереди
  • Применение этой составной функции к каждой строке в последовательности
  • Объединение результатов (неэффективно)

Я бы выделил эти четыре аспекта - в частности, string.Join работает достаточно хорошо для четвертой части, а Enumerable.Select - для третьей.

Я бы также не стал менять порядок операций - я ожидаю, что первая указанная операция будет первой, лично примененной.

Итак, я бы переписал этот метод на return a Func<string, string>, который затем мог бы использоваться с Select и Join. Например:

public static Func<string, string> Compose(params Func<string, string> funcs)
{
    return input => {
        string current = input;
        foreach (var func in funcs)
        {
            current = func(current);
        }
        return current;
    };
}

Конечно, вы могли бы сделать это само по себе, с подписью:

public static Func<T, T> Compose(params Func<T, T> funcs)

Затем вы бы назвали это чем-то вроде:

var composite = Compose<string>(FirstFunction, SecondFunction, ThirdFunction);

var query = string.Join("", items.Select(x => x.ToString())
                                 .Select(composite));
1 голос
/ 14 ноября 2010
public static string WrapEachElementWith
    (   string input, 
        params Func<string, string>[] func )
{
    foreach (var f in func.Reverse())
        input = f(input);
    return input;
}

Не уверен, зачем вам нужен параметр шаблона, все функции отображают строку в строку, верно?

Обратите внимание, что Each расширение IEnumerable отсутствует, поэтому вам придется прибегнуть к foreach или написать свой Each.

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

public static string F<T>
    (   this IEnumerable<T> target, 
        params Func<string, string>[] func )
{
    target.Select(item => WrapEachElementWith(item.ToString(), func))
          .Aggregate((sum, cur) => sum + cur);
}

Как уже упоминал @Jon, суммирование таким способом довольно неэффективно, поэтому, возможно, вы хотели бы выразиться так:

string.Join("", target.Select(
                  item => WrapEachElementWith(item.ToString(), func)));
0 голосов
/ 14 ноября 2010

Этот парень написал весь трассировщик лучей, используя LINQ.Я не очень внимательно изучил его код, но он описывает использование техники, называемой «Y-комбинатор», для создания рекурсии в операторе LINQ.Он ссылается на эту публикацию в блоге , в которой дается подробное описание этих рекурсивных лямбда-выражений.

Я не знаю, действительно ли это то, что вы ищете, но это может вас расстроитьна правильном основании.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...