2011-10-25 116 views
-4

haloa!遞歸獲取ID

我有一個List<Channel>其中Channel是一個自定義類offcourse:

public class Channel 
{ 
    public long ID { get; set; } 
    public long parentID { get; set; } 
} 

晶格結構可以是這樣的:

ID = 1, parentID = 0 
    ID = 64, parentID = 1 
     ID = 28, parentID = 64 
     ID = 36, parentID = 64 
ID = 5, parentID = 0 

等。

我想要做的是讓所有的孩子特定信道的ID的:

function List<long> getChildrenIDS (long ID) 
{ 
    // WHAT GOES HERE? 
} 
+2

你想要孩子的孩子嗎?請爲樣本數據添加一個等級並列出所需的輸出。 –

+0

重複ID 28,這是錯誤的嗎? –

+2

如果'Channel'有一個'List Children {get;私人設置; }'? – Oliver

回答

2

要獲得所有的孩子:

public IEnumerable<long> GetChildren(List<Channel> list, long id) 
{ 
    foreach(Channel c in list) 
    if(c.parentID == id) 
     yield return c.ID; 
} 

構建這是返回一個IEnumerable<long>而不是返回,需要一個List<long>可以使用new List<long>(GetChildren(list, id))GetChildren(list, id).ToList(),同時調用代碼並不需要一個List<long>作爲然後調用代碼這可以在內存和時間上獲得更好的性能,通過不建立它實際上不需要的列表而獲得第一個結果,如foreach(long childID in GetChildren(list, id))

要獲得所有後代(子女,孫子,曾孫等),這是唯一的情況下,我們可以讓任何使用遞歸(根據你的問題的標題)使用方法:

假設有不能重複(通過多種途徑相同的孫子):

private IEnumerable<long> GetDescendants(List<Channel> list, long id) 
{ 
    foreach(long child in GetChildren(list, id)) 
    { 
    yield return child; 
    foreach(long grandchild in GetDescendants(list, child)) 
     yield return grandchild; 
    } 
} 

如果可以有重複,那麼你可以申請.Distinct()以上,或去:

private IEnumerable<long> GetDescHelper(List<Channel> list, long id, HashSet<long> already) 
{ 
    foreach(long child in GetChildren(list, id)) 
    if(already.Add(child)) 
    { 
     yield return child; 
     foreach(long desc in GetDescHelper(list, child, already)) 
     yield return desc; 
    } 
} 
public IEnumerable<long> GetDescendants(List<Channel> list, long id) 
{ 
    return GetDescHelper(list, id, new HashSet<long>()); 
} 

這就是說,我可能更願意讓Channel類保持List<Channel>的孩子。

0

List<Channel> list = new List<Channel>(); 
List<long> ret = new List<long>(); 
在類

,你可以這樣做:

沒有遞歸(所以只有孩子)

private List<long> GetChildrenIds(long parentId) 
{ 
    list.ForEach(p => { if (p.parentID == parentId) ret.Add(p.ID); }); 
    return ret; 
} 

或遞歸(孩子的孩子太)

private List<long> GetChildrenIds(long parentId) 
{ 
    list.ForEach(p => { if (p.parentID == parentId) { 
          ret.Add(p.ID); 
          GetChildrenIds(p.ID); 
         } 
         }); 
    return ret; 
} 
+0

@Dementic:看看我編輯的代碼。這是你需要的嗎? – Marco

+0

在你的類中有ret引入併發問題(兩個線程將被添加到同一個列表中),並且調用該方法兩次的錯誤會產生兩個調用的結果,因爲ret永遠不會被清除。由於ret與類沒有任何關係,但只有在特定的調用時,它才應該是在方法本身中創建的本地。 –

1

不知道馬科斯的回答真的產生期望的結果,但我會以更LINQish時尚寫:

private IEnumerable<long> GetChildrenIds(IEnumerable<Channel> channels, long parentId) 
{ 
    if(channels == null) 
     throw new ArgumentNullException("channels"); 

    var childs = channels.Where(c => c.ParentId == parentId) 
         .Select(c => c.Id); 

    return childs; 
} 

如果您還需要深套的人,你也許可以使用此功能:

private IEnumerable<long> GetAllChildrenIds(IEnumerable<Channel> channels, long parentId) 
{ 
    var childs = GetChildrenIds(channels, parentId); 
    var alldescendants = childs.SelectMany(id => GetAllChildrenIds(channels, id)); 

    return childs.Concat(alldescendants); 
} 

但要注意,它不檢查循環冗餘,並可能在計算器例外結束!

+0

是的,我的答案有效(我試過),但你的解決方案真的很好! :) – Marco

+0

不會這隻得到直接的孩子?那些深嵌的呢? – Dementic

+0

@Dementic:查看我的深層嵌套的更新。 – Oliver