递归IEnumerable不能按预期工作?

Roy*_*mir 5 c# recursion ienumerable

我写了一个递归函数,产生了 IEnumerable<int>

IEnumerable<int>   Go(int b  )
{
 if (b==0) yield  return 0;
   else
 foreach (var element in Go(b-1))
  {
    yield return element;
  }
}
Run Code Online (Sandbox Code Playgroud)

所以,如果我写

foreach (var element in Go(3))
{
    Console.WriteLine (element);
}
Run Code Online (Sandbox Code Playgroud)

它应该屈服

0
1
2
3
Run Code Online (Sandbox Code Playgroud)

但它没有按预期工作.(它显示0).

在正常的递归函数(返回int - 没有Ienumerable)中,它工作正常.

题:

如何修复代码以使其产生预期值?

NB.不,没有理由使用递归的Ienumerables.在玩递归收益后,我才想到这一点.

Bla*_*ear 11

因为你永远不会屈服于b本身而只会屈服于0.

IEnumerable<int> Go(int b)
{
    if(b > 0) {
         foreach (var element in Go(b-1))
            yield return element;
    }
    yield return b;
}
Run Code Online (Sandbox Code Playgroud)

请注意,如果你想要得到的序列从0开始,向上走,你必须yield return b 经过foreach.让我们展开第一个电话Go(3):

Go(3):
foreach(var element in Go(2)):
    yield return element;
yield return 3;
Run Code Online (Sandbox Code Playgroud)

所以3将是序列中的最后一项(因为所有其他项目之前都是yieled).我们现在展开Go(2):

Go(3):
    Go(2):
    foreach(var element in Go(1)):
        yield return element;
    yield return 2;
yield return 3;
Run Code Online (Sandbox Code Playgroud)

Go(1):

Go(3):
    Go(2):
        Go(1):
            foreach(var element in Go(0))
                yield return element;
        yield return 1;
    yield return 2;
yield return 3;
Run Code Online (Sandbox Code Playgroud)

如您所见,结果相对于调用被"向后"链接:

Go(3) --> Go(2) --> Go(1) --> Go(0) --> 0 --> 1 --> 2 --> 3
Run Code Online (Sandbox Code Playgroud)

  • @xanatos我做了3只是为了确定;) (3认同)
  • @BlackBear我花了2分钟来理解你的句子:-)做一个或两个元素的例子:-) (2认同)

Car*_*ten 6

我怀疑它会有什么不同 - 因为yield我看到的唯一具体是yield 0

我想你想要这样的东西:

IEnumerable<int> Go(int b)
{
   if (b > 0)
   {
      foreach (var element in Go(b-1))
      {
        yield return element;
      }
   }
   yield return b;
}
Run Code Online (Sandbox Code Playgroud)

但这仍然是非常低效的,并将用更大的bs 吹掉堆栈


对于你的问题:

你的代码:

会这样做:

b=3:
  is b == 0? no ok, then enumerate and return everything from b=2...
     b=2:
       is b == 0? no ok, then enumerate and return everything from b=1...
         b=1:
           is b == 0? no ok, then enumerate everything from b=0...
             b=0:
               is b == 0? **YES** so yield a single **0**
           everything was {0}
       everything was {0}
  everything was {0}
return is {0}
Run Code Online (Sandbox Code Playgroud)


Gru*_*ndy 4

另一种有条件的变体b==0

static IEnumerable<int> Go(int b)
{
    if (b == 0)
    {
        yield return 0; //return 0 if b==0;
        yield break; // say that iteration end;
    }

    foreach (var el in Go(b - 1)) 
    {
        yield return el;
    }

    yield return b; //return current b as element of result collection

}
Run Code Online (Sandbox Code Playgroud)

或没有yield break

static IEnumerable<int> Go(int b)
{
    if (b == 0)
    {
        yield return 0;
    }
    else
    {

        foreach (var el in Go(b - 1)) 
        {
            yield return el;
        }

        yield return b; //return current b as element of result collection
    }
}
Run Code Online (Sandbox Code Playgroud)