6

背景

我最近读到 .NET 4 的 System.String 类具有 Join 方法的新重载。这个新的重载需要一个分隔符和一个IEnumerable<T>允许将任意集合连接成单个字符串的方法,而无需转换为中间字符串数组。

凉爽的!这意味着我现在可以这样做:

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。

挑战

你能找到一种使用方法链式编程的更简洁的方法吗?

这个挑战是关于尝试在 C# 中找到一种简洁的方式来对具有多个重载的函数进行 curry - 这只是为了好玩!

4

3 回答 3

6

有什么问题:

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

我真的不明白这不是函数式编程。它的链接更少,真的。但是函数式程序不是关于链接,而是关于编写更多的声明性语句,这在我的书中就是这样做的。当然,如果你真的希望它被链接起来,你可以这样做: 什么是 LINQ 内爆/加入字符串数组的方法?

于 2010-04-17T15:31:51.607 回答
1

我不确定您为什么需要示例中的其他 Curry 方法。简单地使用另一个 Lambda 会产生一个更简洁的选项。

var list = Enumerable.Range(1, 100)
    .Where(i => i%2 == 0)
    .ApplyTo((x) => { return string.Join(",", x); })
于 2012-09-05T21:24:31.987 回答
0

五年后仍未得到答复,让我们试试这个!

高效,无需外部代码,完全链接和可读:

var list = Enumerable.Range(1, 100000)
    .Where(i => i % 2 == 0)
    .Aggregate(new StringBuilder(), (prev, i) => prev.AppendFormat(",{0}",i))
    .Remove(0,1)
    .ToString();
于 2015-06-28T21:10:07.507 回答