在“ postorder”中迭代枚举目录。 [英] Enumerating Directories iteratively in "postorder"

查看:81
本文介绍了在“ postorder”中迭代枚举目录。的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我想枚举给定目录的文件&

Suppose I wanted to enumerate through a given directory's files & directories iteratively, in such a way that the inner directories and files are given out first.

如果要在foreach循环中使用以下功能执行此枚举,请使用以下函数:DeleteFile和DeleteEmptyDirectory它应该不会失败,因为最里面的项目会首先产生。

If you were to execute this enumerable in a foreach loop with the functions: DeleteFile and DeleteEmptyDirectory it should not fail, because the most inner items are yielded out first.

现在当然可以做到这一点(伪代码):

Now of course one could do this (pseudocode):

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;

但这浪费了枚举器的大量分配。

But that has wastes a lot of allocations on enumerators.

一个人也可以使用两个堆栈并一起获取所有目录,然后只是不断弹出项目,但这浪费了太多内存,并且不能很好地平衡MoveNext时间。

One could also use two stacks and "acquire" all of the directories together and then just keep popping out items but that wastes too much memory and doesn't balance the MoveNext times that well.

关于如何有效地做到这一点而不浪费太多空间的任何想法?

Any ideas on how to do this efficiently without wasting too much space?

推荐答案

DRY 原则的精神,我会使用答案中的函数来表示如何使IEnumerable树节点的值?

In the spirit of DRY principle, I would use the function from my answer to How to make an IEnumerable of values of tree nodes?

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();
        }
    }
}

在您的情况下使用像这样

Utilizing it for your case would be something like this

var directory = new DirectoryInfo(path);
var result = TreeHelper.Traverse<FileSystemInfo>(directory, fsi => 
    fsi is DirectoryInfo ? ((DirectoryInfo)fsi).EnumerateFileSystemInfos() : null,
    preOrder: false)

这篇关于在“ postorder”中迭代枚举目录。的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆