C# 是否可以编写递归IEnumerable<;T>;
我有一门课,像:C# 是否可以编写递归IEnumerable<;T>;,c#,.net,collections,recursion,ienumerable,C#,.net,Collections,Recursion,Ienumerable,我有一门课,像: class Spline int ChildrenCount; Spline GetChild (int index) class SplineCollection : IEnumerable<Spline> Spline Master 类样条曲线 国际儿童计数; 样条线GetChild(整数索引) 类样条集合:IEnumerable 样条母版 是否可以为SplineCollection编写一个递归IEnumerable,其中它将逐个返
class Spline
int ChildrenCount;
Spline GetChild (int index)
class SplineCollection : IEnumerable<Spline>
Spline Master
类样条曲线
国际儿童计数;
样条线GetChild(整数索引)
类样条集合:IEnumerable
样条母版
是否可以为SplineCollection编写一个递归IEnumerable,其中它将逐个返回所有子对象
编辑:所以Master是根框,其子对象的层次结构可以是任意深度
编辑:通过使用名称框,我想我把一些人弄糊涂了。它应该是一个几何对象,而不是一个容器。因此,将其更改为样条线。是的-有关使用C迭代器的信息,请参见本节。这将对
框进行深度优先遍历。然后,您可以在Master
框中调用此方法以返回所有递归子级
public class Box
{
// ...
public IEnumerable<Box> GetBoxes()
{
yield return this;
for (int i=0; i<box.ChildrenCount; i++)
{
foreach (Box child in box.GetChild(i).GetBoxes())
{
yield return child;
}
}
}
}
公共类框
{
// ...
公共IEnumerable GetBox()
{
收益回报这一点;
对于(int i=0;i类框
{
国际儿童计数;
Box GetChild(int-index){/*一些实现*/}
可数儿童的公共教育
{
得到
{
for(int i=0;i!=ChildrenCount;++i)
收益回报率(i);
}
}
公共数字后裔
{
得到
{
foreach(子对象中的框子对象)
{
退换子女;
foreach(子代中的框描述)
收益率下降;
}
}
}
}
您可以从BoxCollection调用它,但由于Box已经是一个Box的集合,我不知道BoxCollection的用途是什么。因此,让Box实现IEnumerable
或它的一个后代(ICollection
,IList
)可能会提高其有用性
也可以用迭代的方式而不是递归的方式来实现,这有时会有更好的性能(几乎在编译器没有将递归转化为迭代的任何时候),但递归的可读性更高,通常性能更高。当然。您甚至不需要BoxContainer,因为box按其名称作为容器存在:
public class Box
{
private List<Box> myBoxes;
public IEnumerable<Box> GetAllBoxes()
{
yield return this;
foreach (var box in myBoxes)
{
var enumerator = box.GetAllBoxes().GetEnumerator();
while(enumerator.MoveNext())
yield return enumerator.Current;
}
}
}
公共类框
{
私人列表邮箱;
公共IEnumerable GetAllBox()
{
收益回报这一点;
foreach(MyBox中的变量框)
{
var枚举器=box.getAllbox().GetEnumerator();
while(枚举数.MoveNext())
产生返回枚举数。当前;
}
}
}
如果框A包含框B和C,框B包含框D和E,框C包含框F,则可枚举的结果将是A、B、D、E、C、F。是的,但您必须枚举递归结果。您不能只返回它,因为类型不匹配
IEnumerable<int> Triangle(int n) {
yield return n;
if (n > 0)
foreach (var e in Triangle(n - 1))
yield return e;
}
IEnumerable三角形(int n){
收益率n;
如果(n>0)
foreach(三角形中的变量e(n-1))
收益率e;
}
我倾向于手动维护堆栈,而不是依赖这里的调用堆栈。原因是,如果通过递归调用获取子体的方法来使用调用堆栈,则必须为访问的每个样条线创建一个新的IEnumerable
。这将是低效的。您可以显著提高效率通过使用自己的堆栈改进遍历
public IEnumerable<Spline> Descendants
{
get
{
// This performs a simple iterative preorder traversal.
var stack = new Stack<Spline>(new Spline[] { this });
while (stack.Count > 0)
{
Spline current = stack.Pop();
yield return current;
for (int i = current.ChildrenCount - 1; i >= 0; i--)
{
stack.Push(current.GetChild(i));
}
}
}
}
公共IEnumerable子体
{
得到
{
//这将执行一个简单的迭代前序遍历。
var stack=新堆栈(新样条线[]{this});
而(stack.Count>0)
{
样条线电流=stack.Pop();
产生回流电流;
对于(int i=current.ChildrenCount-1;i>=0;i--)
{
stack.Push(current.GetChild(i));
}
}
}
}
这增加了Brian Gideon的伟大答案,只提供了子体,没有根元素。它还使用了foreach
,例如在EF上下文中可能可用
这是我的代码():
//
///检索所有子代。
///
公共数字后裔{
得到{
//这将执行一个简单的迭代前序遍历。
Stack Stack=新堆栈(this.Children);
而(stack.Count>0){
Itemcurrent=stack.Pop();
产生回流电流;
//推电流的孩子们
foreach(current.Children中的项目currentChild){
stack.Push(currentChild);
}
}
}
}
谢谢,但这会通过每个框的子项来完成吗。GetChild(i)也是吗?啊,现在它有意义了。编辑了答案。我认为你写“子项”时是指“后代”,因为获取子对象不需要递归。@Job,是的,你是对的,我指的是后代。只是在我使用的sdk中,它们仍然被称为子对象,ChildrenRecursive,这就是为什么我刚才使用它。你的foreach
有效地导致返回类型为IEnumerable
,与声明的ret不匹配urn类型。我不相信这会在C#中编译。在F#中,您可以将第二个yield
更改为yield!
,它会工作得很好。您完全正确。快速编辑以迭代子框返回的IEnumerable。我希望我可以投票10次。这比递归解决方案效率更高,只需要几秒钟的思考。事实上,您可以将其概括为一个flatte
函数来简化任何递归迭代器。这实际上还返回根元素,而不仅仅是实际的后代。
public IEnumerable<Spline> Descendants
{
get
{
// This performs a simple iterative preorder traversal.
var stack = new Stack<Spline>(new Spline[] { this });
while (stack.Count > 0)
{
Spline current = stack.Pop();
yield return current;
for (int i = current.ChildrenCount - 1; i >= 0; i--)
{
stack.Push(current.GetChild(i));
}
}
}
}
/// <summary>
/// Retrieves all descendants.
/// </summary>
public IEnumerable<Item> Descendants {
get {
// This performs a simple iterative preorder traversal.
Stack<Item> stack = new Stack<Item>(this.Children);
while (stack.Count > 0) {
Itemcurrent = stack.Pop();
yield return current;
//Push current's children
foreach (Item currentChild in current.Children) {
stack.Push(currentChild);
}
}
}
}