【问题标题】:Hides nodes of Tree Object Recursive隐藏树对象递归的节点
【发布时间】:2012-12-30 23:35:36
【问题描述】:

我正在寻找一种在树中隐藏节点的方法。 我正在过滤具有节点类型的节点,这是我的原始结构:

root
 +FolderA
    -File1
    -File2
    -File3
 +FolderB
    -File4
    -File5
    +FolderB-1
            -File6

这就是我想要做的:

+root
 -File1
 -File2
 -File3
 -File4
 -File5
 -File6

我创建了我的类 XNode,其中包含一个类型和一个子项列表。 (这是伪语言的缩写)

Class XNode
  MyType type;
  string Name;
  List<XNode> childrens; 
End Class

我创建了一个工厂类来查询我的数据库并创建原始树。

我创建了一个 Xaml treeView UserControl 来绑定我创建的根 XNode。

无法通过 Xaml 隐藏节点,此操作必须使用绑定对象(我创建的根 Xnode)完成。

现在我的问题是: 有递归算法可以取消“文件夹类型”节点,获取其子节点并将它们添加到父节点?

我试试:

  public XNode RemoveFoldersElements(ref XNode rootNode)
    {

        if (rootNode != null)
        {
            if (rootNode.Children.Count > 0)
            {
                for (int i = 0; i < rootNode.Children.Count; i++)
                {
                    XNode children = rootNode.Children.ElementAt(i);
                    if (children.WType == NodeType.Type_FOLDER)
                    {
                        XNode tempNode = RemoveFoldersElements(ref children);
                        if (tempNode != null)
                            rootNode.Children.Add(tempNode);
                        rootNode.Children.RemoveAt(i);
                    }
                    else
                    {
                        RemoveFoldersElements(ref children);
                    }

                }
            }

        }
        return null;
    }

但不是成功,因为并非所有 Type_FOLDER 节点都被擦除(它跳转一级)! 有什么想法吗?

【问题讨论】:

  • 你可以递归每个节点,构建所有文件的列表,然后将它们作为子节点添加到最后吗?如果您只关心顺序而不关心层次结构,似乎您正在尝试做太多的工作。
  • 这是一种惰性模式。我想过滤具有各种类型项目(不仅是文件)的这棵树
  • 您的示例使用了文件和文件夹,因此我在该上下文中做出了回应。我不明白什么是“懒惰模式”,在递归时将过滤器应用于孩子,并且只使用您想要的类型构建列表。

标签: c# algorithm data-structures recursion tree


【解决方案1】:

好的,想法是这样,在过滤的同时展平树:

public static IEnumerable<TSource> Flatten<TSource>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TSource>> childCollectionSelector, Func<TSource, bool> predicate)
{
    foreach (var item in source)
    {
        if(predicate(item))
            yield return item;
        foreach (var subitem in childCollectionSelector(item).Flatten(childCollectionSelector, predicate).Where(predicate))
        {
            yield return subitem;
        }
    }
}

你可以这样使用它:

var rootList = new []{rootElement}; // Flattening works on the collection
var files = rootList.Flatten(x => x.children, x => x.type == MyType.FILE);

如果您没有任何循环引用并且所有集合都已初始化,它将起作用。如果你确实有循环依赖,你会向StackOverflowException打个招呼...

【讨论】:

  • 我已经尝试过您的解决方案并且它有效,但我必须隐藏不同类型的节点。根节点是一个没有实现 IEnumerable 接口的对象...
  • @user1696549 然后像我在示例中所做的那样将它包装在集合中,这可能是最简单的方法。我不确定你所说的“隐藏不同类型的节点”是什么意思,这是过滤所遗漏的——你必须指定你的过滤功能。
猜你喜欢
  • 2019-03-18
  • 2017-09-26
  • 1970-01-01
  • 1970-01-01
  • 2014-07-12
  • 2018-12-31
  • 1970-01-01
  • 2012-12-12
  • 2020-02-21
相关资源
最近更新 更多