无论如何在C#(或任何其他网络语言)中实现以下目标?
public double nestedParamArrayLoop(function delegatedFunction, LoopControllers loopControllers)
{
double total = 0;
NestedLoopControllers loopControllers = new NestedLoopControllers(loopController, loopMaxes);
foreach(LoopController loopController in loopControllers);
{
nestedfor (loopController)
{
// this line results in one or more loopControllers being passed in
total += delegatedFunction(loopController);
}
}
return total;
}
public double delegatedFunction(params int[] arguments)
{
// dummy function to compute product of values
long product = 1;
for (int i = 0; i < arguments.Count ; i++)
product *= arguments[i];
return product;
}
如果使用可变数量的参数调用delegatedFunction,那么根据数组loopControllers中的控制器数量?每个loopController都包含一个起始值,一个最大值和一个增量值(即模板a for for循环)。
上面的语法并不常用,因为我不确定是否存在捕获此范例。但是这个想法是你可以指定任意数量的嵌套循环,然后由编译器(或运行时)为你完成嵌套。所以它是一种模板化的嵌套,你可以为任意数量的循环定义循环条件,环境为你构造循环。
例如
这样做的目的是避免使用不同数量的参数编写单独的函数,但逻辑的实际内容在它们之间是通用的。
我希望我在解释这个方面做得不错,但如果没有,请问!
答案 0 :(得分:1)
我认为这几乎就是你想做的事情。
从LoopController
定义开始:
public class LoopController : IEnumerable<int>
{
public int Start;
public int End;
public int Increment;
private IEnumerable<int> Enumerate()
{
var i = this.Start;
while (i <= this.End)
{
yield return i;
i += this.Increment;
}
}
public IEnumerator<int> GetEnumerator()
{
return this.Enumerate().GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
现在您可以像这样定义NestedParamArrayLoop
:
public double NestedParamArrayLoop(Func<int[], double> delegatedFunction, List<LoopController> loopControllers)
{
double total = 0;
foreach (LoopController loopController in loopControllers)
{
total += delegatedFunction(loopController.ToArray());
}
return total;
}
现在剩下的很简单:
void Main()
{
var loopControllers = new List<LoopController>()
{
new LoopController() { Start = 4, End = 10, Increment = 2 },
new LoopController() { Start = 17, End = 19, Increment = 1 },
};
Console.WriteLine(NestedParamArrayLoop(DelegatedFunction, loopControllers));
}
public double DelegatedFunction(params int[] arguments)
{
long product = 1;
for (int i = 0; i < arguments.Count(); i++)
product *= arguments[i];
return product;
}
您甚至可以将NestedParamArrayLoop
定义为:
public double NestedParamArrayLoop(Func<int[], double> delegatedFunction, List<LoopController> loopControllers)
{
return
loopControllers
.Select(lc => delegatedFunction(lc.ToArray()))
.Sum();
}
这更像是你之后的事吗?
public double NestedParamArrayLoop(Func<int[], double> delegatedFunction, List<LoopController> loopControllers)
{
Func<IEnumerable<int>, IEnumerable<IEnumerable<int>>> getAllSubsets = null;
getAllSubsets = xs =>
(xs == null || !xs.Any())
? Enumerable.Empty<IEnumerable<int>>()
: xs.Skip(1).Any()
? getAllSubsets(xs.Skip(1))
.SelectMany(ys => new[] { ys, xs.Take(1).Concat(ys) })
: new[] { Enumerable.Empty<int>(), xs.Take(1) };
double total = 0;
foreach (LoopController loopController in loopControllers)
{
foreach (var subset in getAllSubsets(loopController))
{
total += delegatedFunction(subset.ToArray());
}
}
return total;
}
答案 1 :(得分:0)
由于OP要求使用任何.NET语言的解决方案,我在F#中编写了一个(翻译@Enigmativity的答案)。不需要NestedLoopController类:
[[ 4 .. 2 .. 10 ]; [ 17 .. 1 .. 19 ]]
|> Seq.map (fun args ->
(1L, args)
||> Seq.fold (fun a x -> a * int64 x))
|> Seq.sum
|> printfn "%d"
您可以以相对简单的方式将其转换为C#LINQ ......
答案 2 :(得分:0)
我认为你真正需要的是多套笛卡尔积。 Here是Eric Lippert关于在C#中使用任意数量的集合做的好文章。所以创建这样的函数(我不会解释它,因为我不能比Eric在他的文章中做得更好):
static IEnumerable<IEnumerable<T>> CartesianProduct<T>(params IEnumerable<T>[] sources) {
IEnumerable<IEnumerable<T>> result = new[] { Enumerable.Empty<T>() };
foreach (var source in sources) {
var tmp = source;
result = result.SelectMany(
seq => tmp,
(seq, item) => seq.Concat(new[] { item }));
}
return result;
}
然后像这样使用:
foreach (var n in CartesianProduct(Enumerable.Range(1, 4), Enumerable.Range(1, 4))) {
Console.WriteLine(String.Join(", ", n));
// in your case: delegatedFunction(n);
}
输出
1, 1
1, 2
1, 3
1, 4
2, 1
2, 2
2, 3
2, 4
3, 1
3, 2
3, 3
3, 4
4, 1
4, 2
4, 3
4, 4
使用Enumerable.Range
替换LoopController
很容易,Enumerable.Range
仅作为示例使用。