Задача: более аккуратный способ каррирования или частичное применение строки C # 4. - PullRequest
6 голосов
/ 17 апреля 2010

Фон

Недавно я прочитал, что класс System.String в .NET 4 имеет новую перегрузку метода Join. Эта новая перегрузка принимает разделитель и IEnumerable<T>, что позволяет объединять произвольные коллекции в одну строку без необходимости преобразования в массив промежуточных строк.

Cool! Это значит, что теперь я могу сделать это:

var evenNums = Enumerable.Range(1, 100)
    .Where(i => i%2 == 0);
var list = string.Join(",",evenNums);

... вместо этого:

var evenNums = Enumerable.Range(1, 100)
    .Where(i => i%2 == 0)
    .Select(i => i.ToString())
    .ToArray();
var list = string.Join(",", evenNums);

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

Проблема

Однако, будучи фанатом функционального стиля программирования в целом и цепочки методов в C # в частности, я бы предпочел написать что-то вроде этого:

var list = Enumerable.Range(1, 100)
    .Where(i => i%2 == 0)
    .string.Join(",");

Это не законно C #, хотя. Да, я мог бы сделать это с помощью Enumerable.Aggregate, и да, я мог бы сделать это с помощью моего собственного метода расширения Join ), но эти подходы трудно читать / неэффективны и они выглядят как отбой (соответственно), поэтому я хотел бы попробовать и по-другому. Самое близкое, что мне удалось получить, это:

var list = Enumerable.Range(1, 100)
    .Where(i => i%2 == 0)
    .ApplyTo(
        Functional.Curry<string, IEnumerable<object>, string>
            (string.Join)(",")
    );

... используя следующие методы расширения:

public static class Functional
{
    public static TRslt
    ApplyTo<TArg, TRslt>(this TArg arg, Func<TArg, TRslt> func)
    {
        return func(arg);
    }

    public static Func<T1, Func<T2, TResult>>
    Curry<T1, T2, TResult>(this Func<T1, T2, TResult> func)
    {
        Func<Func<T1, T2, TResult>, Func<T1, Func<T2, TResult>>> curried
            = f => x => y => f(x, y);
        return curried(func);
    }
}

Это довольно многословно, требует явного определения параметров и возвращаемого типа строки. Перегрузку, которую я хочу использовать, и она опирается на особенности дисперсии C # 4, потому что мы определяем один из аргументов как IEnumerable, а не IEnumerable.

Задача

Можете ли вы найти более точный способ достижения этого , используя стиль программирования "1035 *?

"

Эта задача состоит в том, чтобы попытаться найти краткий способ, в C #, карри функции, которая имеет несколько перегрузок - и это просто для удовольствия!

Ответы [ 3 ]

6 голосов
/ 17 апреля 2010

Что не так с:

var list = string.Join(",",Enumerable.Range(1, 100).Where(i => i%2 == 0));

Я действительно не понимаю, как это не функциональное программирование. Это меньше цепочки, правда. Но функциональная программа - это не создание цепочки, а написание более декларативных утверждений, что и делается в моей книге. Конечно, если вы действительно хотите, чтобы он был связан в цепочку, вы можете сделать это: Что такое способ LINQ для развертывания / объединения массива строк?

1 голос
/ 06 сентября 2012

Я не уверен, зачем вам нужен дополнительный метод Curry из вашего примера. Простое использование другой лямбды дает более лаконичный вариант.

var list = Enumerable.Range(1, 100)
    .Where(i => i%2 == 0)
    .ApplyTo((x) => { return string.Join(",", x); })
0 голосов
/ 29 июня 2015

Через пять лет это все еще без ответа, давайте попробуем это!

Эффективный, без внешнего кода, полностью цепочечный и читаемый:

var list = Enumerable.Range(1, 100000)
    .Where(i => i % 2 == 0)
    .Aggregate(new StringBuilder(), (prev, i) => prev.AppendFormat(",{0}",i))
    .Remove(0,1)
    .ToString();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...