2010-11-15 86 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. 您可以存儲已過濾的節點列表(黑名單或白名單),然後參考顯示樹時(這涉及最少的代碼更改但處理能力最強)。