【发布时间】:2017-02-28 04:55:06
【问题描述】:
我有一个类型,我们称之为Foo,它可以容纳一组子Foo 对象。 Foo 是一次性的,所以当一个孩子被处置时,它会将自己添加到父级的 Children 集合中。
这个例子的用法如下:
using (var a = AddChild(Root, "a"))
{
using (var a1 = AddChild(a, "a1"))
{
using (var a1a = AddChild(a1, "a1a"))
{
}
}
在此示例中,a1a 仅在处置时添加到 a1,而不是之前。我难以弄清楚的是编写GetAllFoos 方法的简洁方法,该方法以FILO 顺序返回扁平列表中的所有对象。
在这种情况下,我是否只是递归地遍历每个孩子,还是有一些花哨的 LINQ 可以用来尝试合并这些集合?我正在使用它在整个应用程序中拍摄性能测量快照,在某些情况下,我们可能会在配置文件期间调用 GetAllMeasurements,因此方法调用的性能很重要。
这是一个完整的示例应用程序,显示了预期的结果。我必须同时支持 FIFO 和 FILO。我有一个 FIFO 实现工作,但我不确定为 FILO 反向处理这个的最佳方法。
using System;
using System.Collections.Generic;
using System.Linq;
namespace FILO_Example
{
public class Foo : IDisposable
{
internal Foo parent;
public Foo(Foo parent = null)
{
this.parent = parent;
}
public string Name { get; set; }
public List<Foo> Children { get; } = new List<Foo>();
public void Dispose() => this.parent.Children.Add(this);
}
class Program
{
public static Foo Root { get; } = new Foo { Name = "Root" };
static void Main(string[] args)
{
// level 1
using (var a = AddChild(Root, "a"))
{
using (var a1 = AddChild(a, "a1"))
{
using (var a1a = AddChild(a1, "a1a"))
{
}
}
using (var a2 = AddChild(a, "a2"))
{
}
}
using (var b = AddChild(Root, "b"))
{
using (var b1 = AddChild(b, "b1"))
{
}
}
List<Foo> allFoos = GetAllFoosFILO().ToList();
Console.WriteLine(allFoos[0]); // Should be b1
Console.WriteLine(allFoos[1]); // Should be b
Console.WriteLine(allFoos[2]); // Should be a2
Console.WriteLine(allFoos[3]); // Should be a1a
Console.WriteLine(allFoos[4]); // Should be a1
Console.WriteLine(allFoos[5]); // Should be a
}
static IEnumerable<Foo> GetAllFoosFILO()
{
return new List<Foo>();
}
static IEnumerable<Foo> GetAllFoosFIFO()
{
var fooStack = new Stack<Foo>();
fooStack.Push(Root);
while (fooStack.Count > 0)
{
Foo currentFoo = fooStack.Pop();
yield return currentFoo;
// If we have children, add them in reverse order so that it's a First-In-First-Out stack
// then the while loop will yield each child element.
if (currentFoo.Children.Count > 0)
{
List<Foo> fooChildren = currentFoo.Children;
for (int currentIndex = fooChildren.Count - 1; currentIndex >= 0; currentIndex--)
{
fooStack.Push(fooChildren[currentIndex]);
}
}
}
}
static Foo AddChild(Foo parent, string name)
{
var child = new Foo(parent) { Name = name };
return child;
}
}
}
【问题讨论】:
-
如果我理解正确,FILO 是指预购 DFS。那么什么是先进先出——反过来呢?
-
抱歉,我不确定我完全理解 DFS 是什么(我只是在发布此回复之前阅读了一些内容)。我只知道 FILO 意味着我返回最后添加的元素,首先是向后移动。我理解 FIFO 将首先返回添加的第一个元素并继续工作。由于我需要处理以两种不同的顺序遍历集合,这是事后确定的,因此使用 Stack
是不可行的,因为它只是 FILO 而不是 FIFO。 -
DFS 代表Depth First Search。因为你基本上有一棵树。
-
这就是我的理解。再次阅读后,我想我需要应用
Reverse Post-Ordering算法,因为这最适合我的用例。 -
我认为 this example 是我正在寻找的东西,我将完成这个练习,看看它是否能解决我的用例。