在 "postorder" 中迭代枚举目录
Enumerating Directories iteratively in "postorder"
假设我想迭代地枚举给定目录的文件和目录,以先给出内部目录和文件的方式。
如果您要在 foreach 循环中使用函数 DeleteFile 和 DeleteEmptyDirectory 执行此可枚举,它应该不会失败,因为最内部的项目会首先产生。
现在当然可以这样做(伪代码):
func(Directory dir)
foreach (var f in dir.EnumerateFileSystemInfos())
if (f is FileInfo)
yield return f;
else
foreach (var item in func(f))
yield return item;
yield return dir;
但这在枚举器上浪费了大量分配。
也可以同时使用两个堆栈和 "acquire" 所有目录,然后不断弹出项目,但这会浪费太多内存并且不能很好地平衡 MoveNext 时间。
关于如何在不浪费太多的情况下有效地做到这一点的任何想法space?
本着DRY principle, I would use the function from my answer to
的精神
public static class TreeHelper
{
public static IEnumerable<T> Traverse<T>(T node, Func<T, IEnumerable<T>> childrenSelector, bool preOrder = true)
{
var stack = new Stack<IEnumerator<T>>();
var e = Enumerable.Repeat(node, 1).GetEnumerator();
try
{
while (true)
{
while (e.MoveNext())
{
var item = e.Current;
var children = childrenSelector(item);
if (children == null)
yield return item;
else
{
if (preOrder) yield return item;
stack.Push(e);
e = children.GetEnumerator();
}
}
if (stack.Count == 0) break;
e.Dispose();
e = stack.Pop();
if (!preOrder) yield return e.Current;
}
}
finally
{
e.Dispose();
while (stack.Count != 0) stack.Pop().Dispose();
}
}
}
将它用于你的情况就像这样
var directory = new DirectoryInfo(path);
var result = TreeHelper.Traverse<FileSystemInfo>(directory, fsi =>
fsi is DirectoryInfo ? ((DirectoryInfo)fsi).EnumerateFileSystemInfos() : null,
preOrder: false)
假设我想迭代地枚举给定目录的文件和目录,以先给出内部目录和文件的方式。
如果您要在 foreach 循环中使用函数 DeleteFile 和 DeleteEmptyDirectory 执行此可枚举,它应该不会失败,因为最内部的项目会首先产生。
现在当然可以这样做(伪代码):
func(Directory dir)
foreach (var f in dir.EnumerateFileSystemInfos())
if (f is FileInfo)
yield return f;
else
foreach (var item in func(f))
yield return item;
yield return dir;
但这在枚举器上浪费了大量分配。
也可以同时使用两个堆栈和 "acquire" 所有目录,然后不断弹出项目,但这会浪费太多内存并且不能很好地平衡 MoveNext 时间。
关于如何在不浪费太多的情况下有效地做到这一点的任何想法space?
本着DRY principle, I would use the function from my answer to
public static class TreeHelper
{
public static IEnumerable<T> Traverse<T>(T node, Func<T, IEnumerable<T>> childrenSelector, bool preOrder = true)
{
var stack = new Stack<IEnumerator<T>>();
var e = Enumerable.Repeat(node, 1).GetEnumerator();
try
{
while (true)
{
while (e.MoveNext())
{
var item = e.Current;
var children = childrenSelector(item);
if (children == null)
yield return item;
else
{
if (preOrder) yield return item;
stack.Push(e);
e = children.GetEnumerator();
}
}
if (stack.Count == 0) break;
e.Dispose();
e = stack.Pop();
if (!preOrder) yield return e.Current;
}
}
finally
{
e.Dispose();
while (stack.Count != 0) stack.Pop().Dispose();
}
}
}
将它用于你的情况就像这样
var directory = new DirectoryInfo(path);
var result = TreeHelper.Traverse<FileSystemInfo>(directory, fsi =>
fsi is DirectoryInfo ? ((DirectoryInfo)fsi).EnumerateFileSystemInfos() : null,
preOrder: false)