我正在试图弄清楚如何使用LINQ来限制递归调用。
我使用以下代码的意图是运行一个数字列表(num
),并为每个数字递归计数/打印到设定数量(6
)。
我想要获得的newnum
中的序列是:3 4
五
1
2
3
4
五
五
2
3
4
5
但我自然而然地遇到了无限循环。 .Where
谓词并没有像我想象的那样停止循环,而且我的基本情况很可能已经关闭。有关正确设置方法的任何见解?谢谢。
var num = new[] {3, 1, 8, 5, 2};
Func<int, int> writeString = delegate(int count)
{
Func<int, int> recursiveWrite = null;
recursiveWrite = n =>
{
Console.WriteLine("string " + n);
recursiveWrite(n+1);
return n;
};
return recursiveWrite(count);
};
var newnum = num.Where(n => writeString(n) < 6); // is this possible?
newnum.ToList().ForEach( w => Console.WriteLine(w));
我注意到以下示例代码中出现了类似的停止模式,.Where
只包含小于7的阶乘,我缺少什么?
var numbers = new[] { 5,1,3,7,2,6,4};
Func<int, int> factorial = delegate(int num) {
Func<int, int> locFactorial = null;
locFactorial = n => n == 1 ? 1 : n * locFactorial(n - 1);
return locFactorial(num);
};
var smallnums = numbers.Where(n => factorial(n) < 7);
答案 0 :(得分:4)
答案是你没有拥有基本案例。一旦你的递归函数被执行,没有什么可以阻止它 - LINQ不执行任何可以修改另一个函数的内部逻辑的魔法。
在示例中,您缺少将停止递归的这一关键代码 - 基本情况:
locFactorial = n => n == 1 ? 1 : n * locFactorial(n - 1);
三元运算符检查是否n==1
- 如果是,则返回1 。这是你的功能缺乏的基本情况。
单独通过LINQ无法为您的函数提供基本案例。你需要将它构建到递归函数中。
此外,如果要从单个数字返回数字列表,则从递归函数返回错误的类型:这与Factorial
函数的基本情况不同给出一个数字,返回单个数字。
这是一个在不使用递归的情况下执行所需操作的函数:
void Main()
{
var numbers = new[] {3, 1, 8, 5, 2};
numbers.SelectMany(x => GetIncreasing(x).TakeWhile(y => y < 6));
}
IEnumerable<int> GetIncreasing(int x)
{
while (true)
yield return x++;
}
答案 1 :(得分:2)
您可以坚持使用符合您要求的生成序列,例如:
var num = new[] { 3, 1, 8, 5, 2 };
var limit = 6;
var query = from n in num
where n < limit // sanity check
from pn in Enumerable.Range(n, limit - n)
select pn;
体面的表现和干净的代码
答案 2 :(得分:1)
与阶乘样本的不同之处在于最终条件的放置。这是你应该做的:
recursiveWrite = n =>
{
Console.WriteLine("string " + n);
if (n < 6)
recursiveWrite(n+1);
return n;
};
答案 3 :(得分:1)
不完全确定你想要实现的目标,但我希望这会有所帮助。 在递归lambda中需要一个停止条件(因为n == 1在factorial中)。 使用嵌套的func,您可以“动态”注入此限制。
class Program
{
static void Main(string[] args)
{
var num = new[] { 3, 1, 8, 5, 2 };
Func<int, Func<int, IEnumerable<int>>> writeString =
delegate(int maxcount)
{
Func<int, IEnumerable<int>> recursiveWrite = null;
recursiveWrite = (n) =>
{
if (n < maxcount)
{
Console.WriteLine("string " + n);
var rec = recursiveWrite(n + 1);
return new List<int>(){n}.Concat(rec);
}
return new List<int>();
};
return recursiveWrite;
};
var newnum = num.SelectMany(n => writeString(6)(n)); // is this possible?
newnum.ToList().ForEach(w => Console.WriteLine(w));
Console.ReadLine();
}
}