2011-10-12 82 views
3

刪除項目我有以下結構的樹形視圖:遞歸從樹

var myTree = myRepository.GetTree(); 

凡客體文件夾這樣的結構:

public class Folder 
{ 
    public string Name { get; set; } 
    public List<Folder> Folders { get; set; } 
    public Folder Parent { get; set; } 
} 

假設一個信息庫返回我有這樣的結構:

MyFolder 
    -MyChild01 
    -MyChild02 
     -MySubChild01  
    -MyChild03 
     -MySubChild02 

我需要遞歸讀取樹中的所有項目並且如果項目的名稱包含'02'我必須從樹中刪除項目。因此,最終的結果應該是:

MyFolder 
    -MyChild01 
    -MyChild03 

我想看看如何使用遞歸LINQ與匿名委託或用遞歸函數來做到這一點。

回答

5

您可以採取多種方法來做到這一點。

最簡單的做法是採取功能性方法並遞歸重建樹,排除與您的模式相匹配的文件夾。

static Folder Filtered(Folder root, Func<Folder, bool> predicate) 
{ 
    return new Folder 
    { 
     Name = root.Name, 
     Parent = root.Parent, 
     Folders = root.Folders 
      .Where(predicate) 
      .Select(subFolder => Filtered(subFolder, predicate)) 
      .ToList(), 
    }; 
} 

Folder myTree = ...; 
var filtered = Filtered(myTree, f => f.Name.Contains("02")); 

如果因任何原因,你寧願不使您的文件夾的新實例,但寧願修改現有的情況下,一些調整就必須進行,但仍然同樣簡單。

static Folder Filtered(Folder root, Func<Folder, bool> predicate) 
{ 
    // make use of the RemoveAll() method for lists 
    root.Folders.RemoveAll(subFolder => !predicate(subFolder)); 
    foreach (var subFolder in root.Folders) 
    { 
     Filtered(subFolder, predicate); 
    } 
    return root; 
} 
+0

我打算選擇這一個,因爲我無法進行更改並創建新的實例,但我必須保持現有實例已過濾,並且此文章解釋了這一點。 – Raffaeu

+0

輝煌 - 正是我期待的(第二個例子)謝謝! –

1
static void Main(string[] args) 
    { 
     var root = new Folder() 
     { 
      Name = "MyFolder", 
      Folders = new List<Folder>(){ 
        new Folder() {Name="MyChild01", Folders = new List<Folder>()}, 
        new Folder() {Name="MyChild02", Folders = new List<Folder>(){ 
         new Folder() { Name="MySubChild01", Folders = new List<Folder>()}} 
        }, 
        new Folder() {Name="MyChild03", Folders = new List<Folder>(){ 
         new Folder() { Name="MySubChild02", Folders = new List<Folder>()}} 
        }, 
       } 
     }; 

     var filtered = applyFilter(root, f=>!f.Name.EndsWith("02")); 

    } 

    static Folder applyFilter(Folder root, Predicate<Folder> filter) 
    { 
     var result = new Folder() { Name = root.Name, Parent = root.Parent }; 
     result.Folders = (from child in root.Folders 
         where filter(child) 
         select applyFilter(child, filter)).ToList(); 
     return result; 
    }