2010-11-15 64 views
2

我有一个分层的对象列表。假设结构如下:递归搜索分层列表

  • 根节点
    • 父节点
      • 子节点
    • 父节点
      • 子节点
    • 父节点
      • 子节点

子节点可以有自己的孩子,但目标是基本搜索“父节点”。所以,假设父节点类有一个名为“Name”的属性 - 并且用户输入了一个部分名称,我想要返回其名称中包含用户搜索条件的所有父节点。基本上,这比其他任何东西都更具“过滤”功能。所以,我知道如何做到这一点,但是我遇到的问题是他们的主要目标是保持层级结构的机智。换句话说,如果有符合过滤条件的一个父节点,我想下面要返回的结构:

  • 根节点
    • 父节点
      • 子节点

我目前的努力只产生:

  • 父节点

我使用LINQ

  • 子节点。任何建议将不胜感激。

    谢谢!

    克里斯

    代码片断低于当前滤波器的实现:

    FilteredReports = Reports.FirstOrDefault().Children.Cast<IHierarchicalResult>() 
                .SelectRecursive(item => item.Children.Cast<IHierarchicalResult>()) 
                .Where(item => item.Name.ToLower().StartsWith(filterCriteria)) 
                .ToObservableCollection(); 
    

    这里是扩展方法,我使用:

    public static IEnumerable<T> SelectRecursive<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> getChildren) 
        { 
         if (null == source) 
         { 
          throw new ArgumentNullException("source"); 
         } 
    
         if (null == getChildren) return source; 
    
         return SelectRecursiveIterator(source, getChildren); 
        } 
    
        private static IEnumerable<T> SelectRecursiveIterator<T>(IEnumerable<T> source, Func<T, IEnumerable<T>> getChildren) 
        { 
         foreach (T item in source) 
         { 
          yield return item; 
    
          IEnumerable<T> children = getChildren(item); 
          if (null != children) 
          { 
           foreach (T child in SelectRecursiveIterator(children, getChildren)) 
           { 
            yield return child; 
           } 
          } 
         } 
        } 
    
+0

您能否给我们提供更多信息?你的分层列表是什么类型的集合?子节点是封装在父节点中还是与树型结构相关联?代码片段很好! – 2010-11-15 16:12:17

+0

集合是一个ObservableCollection。每个节点都有一个名为Children的属性 - 这是同一类的IEnumerable集合。因此,为了保持这个要求简单,使用扩展方法或其他一些干净的方法,我可以过滤根节点的初始子节点,并且仍然保持根节点的机制? – Chris 2010-11-15 16:21:14

+0

我认为我需要有两个集合。一个集合是对象的原始集合,第二个集合将是我的动态集合,它表示已过滤的结果。我也不想假设我总是只有一个根节点。 – Chris 2010-11-15 16:21:46

回答

5

由于您要返回的根节点与原始根节点(其子节点较少)不同,因此您需要创建一个仅包含匹配的子节点的新根节点。

喜欢的东西

Node oldRootNode = ... 
    List<Node> filteredChildren = oldRootNode.Children.Where(...).ToList(); 
    Node newRootNode = new Node {Name = oldRootNode.Name, Children = filteredChildren}; 

    return newRootNode; 
+0

我喜欢这个解决方案。如果您不介意复制根节点,并且只需要在第一个子集合上进行筛选,那么我会使用这个。 – Kendrick 2010-11-15 16:16:25

0

从内存(可能含有错别字),并基于不知道你的代码:

var filteredList = myRootNode.CollectionOfParentNodes.Where(p => p.Name.Contains(searchCriteriaString)).ToList(); 
+0

他想要树结构,而不是列表。 – Kendrick 2010-11-15 16:11:09

+0

好吧,我错读了这个问题,回答太快。不包含原始根节点。 Hightechrider的回答对我来说很合适。 – 2010-11-15 16:15:22

0

有几件事情,你可以在这里做。

  1. 您可以创建主体结构的副本,并从过滤器返回它(浅复制尽可能多的,但你必须要深拷贝节点之间的链接)
  2. 您可扩展节点了解他们是否被过滤(即IsFilteredOut,ChildrenUnfilteredGet()等),然后显示“过滤”树。
  3. 您可以存储已过滤的节点列表(黑名单或白名单),然后参考显示树时(这涉及最少的代码更改但处理能力最强)。