2017-02-18 19 views
0

我不知道這個問題的正確命名。基於雲有多少路徑,這是將層次列表轉換爲列表的更快方法嗎?

定義很簡單,這是一個層次列表(我也能產生扁平列表)

Simply show hierarchy view 
hierarchy I able to get 
1 
-->2 
-->3 
    -->4 
    -->5 
-->6 

flattened list I able to get 
[1, 2, 3, 4, 5, 6] 

結果我想是

[ 
    [1,2], 
    [1,3,4], 
    [1,3,5], 
    [1,6], 
] 

樣品I類有

public class MemberNetworkViewModel 
{ 
    public int MemberGenerationNumber { get; set; } 
    public int MemberId { get; set; } 
    public int ParentId{ get; set; } 
    public List<MemberNetworkViewModel> children { get; set; } 
} 

我可以做最困難的方法,試圖獲得誰是這個層次列表中的最後一個節點,然後foeeach他們並一一得到他們的父母。但我認爲會有更好的方式,有什麼想法?

當前解決方案(旁路,我所知道的是凌亂的,尋求通過LINQ較短的幫助也許?)

public List<List<MemberNetworkViewModel>> GetAllPossibleNetworkTreePath(
     List<MemberNetworkViewModel> flatternMemberNetworkViewModel) 
    { 
     var possibleTreePaths = new List<List<MemberNetworkViewModel>>(); 

     var lastNodes = 
      flatternMemberNetworkViewModel.Where(
       x => flatternMemberNetworkViewModel.All(y => y.ParentId!= x.MemberId)); 

     foreach (var lastNode in lastNodes) 
     { 
      var memberNetworkViewModels = new List<MemberNetworkViewModel>(); 
      memberNetworkViewModels.Add(lastNode); 
      for (int index = 0; index < lastNode.MemberGenerationNumber; index++) 
      { 
       var parent = 
        flatternMemberNetworkViewModel.FirstOrDefault(
         x => x.MemberId == memberNetworkViewModels.Last().ParentId); 
       memberNetworkViewModels.Add(parent); 
      } 
      memberNetworkViewModels = (from x in memberNetworkViewModels 
       orderby x.MemberGenerationNumber 
       select x).ToList(); 

      possibleTreePaths.Add(memberNetworkViewModels); 
     } 

     return possibleTreePaths; 
    } 
+0

好像曲..我會使用一個樹而不是 –

+0

然後你的子列表只是從根到葉的路徑,如果你需要它們可以很容易地獲得 –

+0

@CedricDruck,因爲我需要根據樹路徑做一些檢查。我非常好奇,但這是客戶要求的。所以我認爲我自己的建議是更好的方法? –

回答

4

如果你有一個樹源數據就變得容易多了。

它看起來像你已經有一棵樹,以列表的形式舉行。您只需要知道列表中代表根的元素,並將其用作遍歷樹的起點。

您可以編寫一個通用的方法來遍歷樹和輸出像這樣的路線,所有的葉子:

public static void Flatten<T, U>(T root, Func<T, U> select, Func<T, IEnumerable<T>> children, Action<List<U>> output) 
{ 
    List<U> pathSoFar = new List<U>(); 
    flatten(pathSoFar, root, select, children, output); 
} 

static void flatten<T, U>(List<U> pathSoFar, T root, Func<T, U> select, Func<T, IEnumerable<T>> children, Action<List<U>> output) 
{ 
    pathSoFar.Add(select(root)); 
    bool any = false; 
    var offspring = children(root); 

    if (offspring != null) 
    { 
     foreach (var child in offspring) 
     { 
      any = true; 
      flatten(pathSoFar, child, select, children, output); 
     } 
    } 

    if (!any) 
     output(pathSoFar.ToList()); 

    pathSoFar.RemoveAt(pathSoFar.Count-1); 
} 

您傳遞爲output參數的函數功能將一次爲每個路徑被稱爲一片葉子。

一個完整的編譯控制檯這將對您輸入的應用程序如下:

using System; 
using System.Linq; 
using System.Collections.Generic; 

namespace ConsoleApp3 
{ 
    class Node 
    { 
     public int ID; 
     public List<Node> Children; 
    } 

    public class MemberNetworkViewModel 
    { 
     public int MemberGenerationNumber { get; set; } 
     public int MemberId { get; set; } 
     public int ParentId { get; set; } 
     public List<MemberNetworkViewModel> children { get; set; } 
    } 

    class Program 
    { 
     public static void Main(string[] args) 
     { 
      Node root = 
       new Node {ID = 1, Children = new List<Node>{ 
        new Node {ID = 2 }, 
        new Node {ID = 3, Children = new List<Node>{ 
         new Node {ID = 4}, 
         new Node {ID = 5}}}, 
        new Node {ID = 6} 
       }}; 

      Flatten(
       root, 
       node => node.ID, 
       node => node.Children, 
       path => Console.WriteLine(string.Join(", ", path))); 
     } 

     public static void Flatten<T, U>(T root, Func<T, U> select, Func<T, IEnumerable<T>> children, Action<List<U>> output) 
     { 
      List<U> pathSoFar = new List<U>(); 
      flatten(pathSoFar, root, select, children, output); 
     } 

     static void flatten<T, U>(List<U> pathSoFar, T root, Func<T, U> select, Func<T, IEnumerable<T>> children, Action<List<U>> output) 
     { 
      pathSoFar.Add(select(root)); 
      bool any = false; 
      var offspring = children(root); 

      if (offspring != null) 
      { 
       foreach (var child in offspring) 
       { 
        any = true; 
        flatten(pathSoFar, child, select, children, output); 
       } 
      } 

      if (!any) 
       output(pathSoFar.ToList()); 

      pathSoFar.RemoveAt(pathSoFar.Count-1); 
     } 
    } 
} 

爲了您MemberNetworkViewModel類,你會調用它像這樣:

MemberNetworkViewModel root = whatever; 

Flatten(
    root, 
    node => node.MemberId, 
    node => node.children, 
    path => Console.WriteLine(string.Join(", ", path))); 
+0

看起來非常好,但爲什麼'pathSoFar.ToList()'?通過刪除遞歸中添加的元素,可以輕鬆避免大量列表(和底層數組)複製。 –

+1

@KrisVandermotten這是真的;我只是爲了簡單。我修改了代碼,以防止製作這麼多副本 - 但請注意,我仍然爲每個返回的列表製作一份副本(必須完成,否則返回的列表會在迭代過程中保持不斷變化!) –

+0

@MatthewWatson這非常令人驚訝!看起來我會更多地研究'Func,Action和generic' –

相關問題