2013-10-15 106 views
3

我正在尋找將數據從平面列表轉換爲層次結構。我怎樣才能以可讀的方式來完成這個工作,但在性能上仍然可以接受,並且我可以利用任何.NET庫。我認爲這被認爲是某些術語(在這種情況下由行業)的「方面」。將平面陣列中的數據轉換爲層次結構

public class Company 
{   
    public int CompanyId { get; set; } 
    public string CompanyName { get; set; } 
    public Industry Industry { get; set; } 
} 

public class Industry 
{ 
    public int IndustryId { get; set; } 
    public string IndustryName { get; set; } 
    public int? ParentIndustryId { get; set; } 
    public Industry ParentIndustry { get; set; } 
    public ICollection<Industry> ChildIndustries { get; set; } 
} 

現在讓我們假設我有一個List<Company>,我期待將其改造成一個List<IndustryNode>

//Hierarchical data structure 
public class IndustryNode 
{ 
    public string IndustryName{ get; set; } 
    public double Hits { get; set; } 
    public IndustryNode[] ChildIndustryNodes{ get; set; } 
} 

這樣得到的對象應該是這樣的下面後,序列化:

{ 
    IndustryName: "Industry", 
    ChildIndustryNodes: [ 
     { 
      IndustryName: "Energy", 
      ChildIndustryNodes: [ 
       { 
        IndustryName: "Energy Equipment & Services", 
        ChildIndustryNodes: [ 
         { IndustryName: "Oil & Gas Drilling", Hits: 8 }, 
         { IndustryName: "Oil & Gas Equipment & Services", Hits: 4 } 
        ] 
       }, 
       { 
        IndustryName: "Oil & Gas", 
        ChildIndustryNodes: [ 
         { IndustryName: "Integrated Oil & Gas", Hits: 13 }, 
         { IndustryName: "Oil & Gas Exploration & Production", Hits: 5 }, 
         { IndustryName: "Oil & Gas Refining & Marketing & Transporation", Hits: 22 } 
        ] 
       } 
      ] 
     }, 
     { 
      IndustryName: "Materials", 
      ChildIndustryNodes: [ 
       { 
        IndustryName: "Chemicals", 
        ChildIndustryNodes: [ 
         { IndustryName: "Commodity Chemicals", Hits: 24 }, 
         { IndustryName: "Diversified Chemicals", Hits: 66 }, 
         { IndustryName: "Fertilizers & Agricultural Chemicals", Hits: 22 }, 
         { IndustryName: "Industrial Gases", Hits: 11 }, 
         { IndustryName: "Specialty Chemicals", Hits: 43 } 
        ] 
       } 
      ] 
     } 
    ] 
} 

其中「命中」是屬於該組的公司數量。

爲了澄清,我需要一個List<Company>轉換成List<IndustryNode>不序列化List<IndustryNode>

+0

你是什麼意思的效率?最具可讀性和可維護性或最佳性能? – CookieOfFortune

+0

對不起,我沒有說清楚。它需要有效,但我願意爲可讀性和可維護性做一些折衷 – parliament

+0

最終它將被序列化 – parliament

回答

1

試試這個:

private static IEnumerable<Industry> GetAllIndustries(Industry ind) 
    { 
     yield return ind; 
     foreach (var item in ind.ChildIndustries) 
     { 
      foreach (var inner in GetAllIndustries(item)) 
      { 
       yield return inner; 
      } 
     } 
    } 

    private static IndustryNode[] GetChildIndustries(Industry i) 
    { 
     return i.ChildIndustries.Select(ii => new IndustryNode() 
     { 
      IndustryName = ii.IndustryName, 
      Hits = counts[ii], 
      ChildIndustryNodes = GetChildIndustries(ii) 
     }).ToArray(); 
    } 


    private static Dictionary<Industry, int> counts; 
    static void Main(string[] args) 
    { 
     List<Company> companies = new List<Company>(); 
     //... 
     var allIndustries = companies.SelectMany(c => GetAllIndustries(c.Industry)).ToList(); 
     HashSet<Industry> distinctInd = new HashSet<Industry>(allIndustries); 
     counts = distinctInd.ToDictionary(e => e, e => allIndustries.Count(i => i == e)); 
     var listTop = distinctInd.Where(i => i.ParentIndustry == null) 
         .Select(i => new IndustryNode() 
           { 
            ChildIndustryNodes = GetChildIndustries(i), 
            Hits = counts[i], 
            IndustryName = i.IndustryName 
           } 
         ); 
    } 

未經檢驗

+0

'distrinctInd.Where(i => i.ParentIndustry == null)'不匹配任何元素,因爲公司從未引用任何頂級行業元素。我一直在努力使其工作,但仍然有很多困難。 – parliament

+0

嘗試'distinctInd.Where(i => i.ChildIndustries == null || i.ChildIndustries.Count == 0)' –

0

你正在尋找一個串行器。 MSFT有一個原生的VS,但我喜歡免費的Newtonsofts。 MSFT文檔和示例是here,Newtonsoft文檔是here

Newtonsoft免費,簡單,快捷。

+0

我真的不喜歡有人給我一個沒有理由的減號。如果您沒有理由,請不要投票。 – CodeChops

+0

我沒有downvote,但答案是沒有幫助的。我已經在使用JSON.NET進行序列化了,但是我仍然需要將它應用到適當的結構中。 – parliament

+0

原來的帖子中並沒有明確的答案(如答案的一半所證明)。這聽起來像你在尋找性能。對不起,我誤解了你的問題。我仍然認爲減去一個東西並不解釋你的理由是很糟糕的。 – CodeChops

0

嘗試使用json序列化程序來達到此目的。我看到你的數據結構是可以的,這只是一個序列化問題。

var industryNodeInstance = LoadIndustryNodeInstance(); 

var json = new JavaScriptSerializer().Serialize(industryNodeInstance); 

如果你想串行之間進行選擇,請看到這一點: http://www.servicestack.net/benchmarks/#burningmonk-benchmarks

LoadIndustryNodeInstance方法

  • 構建List<Industry>

  • 轉換IndustryTree = List<IndustryNode>

  • 實現Tree方法,例如遍歷。嘗試看看 Tree data structure in C#

+0

這個問題涉及'LoadIndustryNodeInstance()'中發生了什麼。我有一個'List '而不是'List ' – parliament

0

下面是一些僞代碼,可能讓你前進的道路。我創建了一個地圖/字典索引並用公司列表填充它。然後我們從索引中提取頂級節點。請注意,可能存在邊緣情況(例如,此索引最初可能需要部分填充,因爲似乎您的任何公司都沒有引用頂級節點,因此這些索引必須以其他方式填充) 。

Dictionary<String, IndustryNode> index = new Dictionary<String, IndustryNode>(); 

public void insert(Company company) 
{ 
    if(index.ContainsKey(company.Industry.IndustryName)) 
    { 
     index[company.Industry.IndustryName].hits++; 
    } 
    else 
    { 
     IndustryNode node = new IndustryNode(IndustryName=company.Industry, Hits=1); 
     index[node.IndustryName] = node; 
     if(index.ContainsKey(company.Industry.ParentIndustry.IndustryName)) 
     { 
      index[company.Industry.ParentIndustry.IndustryName].ChildrenIndustries.Add(node); 
     } 
    }  
} 

List<IndustryNode> topLevelNodes = index 
    .Where(kvp => kvp.Item.ParentIndustry == null) 
    .ToList(kvp => kvp.Item); 
+0

如果這個解決方案不受公司影響,那麼這個解決方案就不會考慮到這個行業的兒童。 –

+0

@AhmedKRAIEM確實,這些必須先插入。 – CookieOfFortune

+0

感謝您的回答,如果這種方法採取了行業,而不是遞歸可應用於處理兒童案件的孩子? – parliament

相關問題