给定一个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;
}
如何简化/重构?
更新: 我应该提供更多背景资料。在看到高阶JavaScript会话和John在Oredev的滥用c#会话后,我正在使用c#中的函数编程。
目的是生成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;
}
答案 0 :(得分:3)
在我看来,你做了四件事:
我会将这四个方面分开 - 特别是string.Join
对第四部分有效,Enumerable.Select
做第三部分。
我也会避免颠倒操作的顺序 - 我希望我指定的第一个操作是第一个应用的操作,个人。
所以,我会将此方法重写为 return 一个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 :(得分:1)
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
。
编辑:
您的代码实际上将此函数应用于列表中的所有值,因此实际代码将类似于:
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)));
答案 2 :(得分:0)
This guy使用LINQ编写了一个完整的光线跟踪器。我没有密切关注他的代码,但他描述了使用一种称为“Y-combinator”的技术在LINQ语句中创建递归。他引用了this blog posting,它详细描述了这些递归的lambda表达式。
我不知道这是不是你想要的,但它可能会让你站稳脚跟。