2013-08-13 17 views
5

Ho un set di dati che contiene 4 colonne. Nome, chiave, parentkey, livello. Devo convertire questo DataTable in una struttura ad albero. Allego un'immagine che ti darà un'idea di ciò che voglio fare. Qual è il modo più efficiente per convertire DataTable in un oggetto che è possibile utilizzare per generare una struttura ad albero. Per favore aiuto.Conversione del risultato della tabella dati nell'albero mediante C#

Nota: I dati possono arrivare in qualsiasi ordine in DataTable. È possibile ordinare il dataTable nella colonna di primo livello e quindi nella colonna parentKey? Penso che, se posso farlo, sarebbe facile convertire l'output in una struttura ad albero.

enter image description here

ho aggiunto una classe che imitano il set di dati & ho ordinato i dati all'interno del datatable.

namespace SortDataTable 
{ 


    public class Program 
    { 
     private static void Main(string[] args) 
     { 
      DataTable table = new DataTable(); 
      table.Columns.Add("Name", typeof (string)); 
      table.Columns.Add("Key", typeof (string)); 
      table.Columns.Add("ParentKey", typeof (string)); 
      table.Columns.Add("Level", typeof (int)); 


      table.Rows.Add("A", "A1", null, 1); 
      table.Rows.Add("B", "A2", "A1", 2); 
      table.Rows.Add("C", "A3", "A1", 2); 
      table.Rows.Add("D", "A4", "A1", 2); 

      table.Rows.Add("E", "A5", "A2", 3); 
      table.Rows.Add("F", "A6", "A5", 4); 
      table.Rows.Add("G", "A7", "A3", 3); 
      table.Rows.Add("H", "A8", "A4", 3); 


      table.Rows.Add("I", "A9", "A4", 3); 
      table.Rows.Add("J", "A10", "A4", 3); 
      table.Rows.Add("K", "A11", "A10", 4); 
      table.Rows.Add("L", "A12", "A10", 4); 

      table.Rows.Add("M", "A13", "A12", 5); 
      table.Rows.Add("N", "A14", "A12", 5); 
      table.Rows.Add("O", "A15", "A10", 4); 

      DataView view = table.DefaultView; 

      // By default, the first column sorted ascending. 
      view.Sort = "Level, ParentKey DESC"; 


      foreach (DataRowView row in view) 
      { 
       Console.WriteLine(" {0} \t {1} \t {2} \t {3}", row["Name"], row["Key"], row["ParentKey"], row["Level"]); 
      } 
      Console.ReadKey(); 

     } 

    } 


    public class Node<T> 
    { 
     internal Node() { } 
     public T Item { get; internal set; } 
     public int Level { get; internal set; } 
     public Node<T> Parent { get; internal set; } 
     public IList<Node<T>> Children { get; internal set; } 



     public static IEnumerable<Node<T>> ToHierarchy<T>(IEnumerable<T> source, Func<T, bool> startWith, Func<T, T, bool> connectBy) 
     { 
      if (source == null) throw new ArgumentNullException("source"); 
      if (startWith == null) throw new ArgumentNullException("startWith"); 
      if (connectBy == null) throw new ArgumentNullException("connectBy"); 
      return source.ToHierarchy(startWith, connectBy, null); 
     } 

     private static IEnumerable<Node<T>> ToHierarchy<T>(IEnumerable<T> source, Func<T, bool> startWith, Func<T, T, bool> connectBy, Node<T> parent) 
     { 
      int level = (parent == null ? 0 : parent.Level + 1); 

      var roots = from item in source 
         where startWith(item) 
         select item; 
      foreach (T value in roots) 
      { 
       var children = new List<Node<T>>(); 
       var newNode = new Node<T> 
       { 
        Level = level, 
        Parent = parent, 
        Item = value, 
        Children = children.AsReadOnly() 
       }; 

       T tmpValue = value; 
       children.AddRange(source.ToHierarchy(possibleSub => connectBy(tmpValue, possibleSub), connectBy, newNode)); 

       yield return newNode; 
      } 
     } 
    } 





} 
+0

Struttura ad albero di cosa? Una classe? –

+0

Non è necessario il "Livello". Key e ParentKey sono sufficienti per costruire alberi illimitati in una tabella autoreferenziale. – Robert

+0

@SriramSakthivel: Sì. struttura ad albero di una classe. – SharpCoder

risposta

3

Io uso il seguente metodo di estensione per fare questo genere di cose:

public class Node<T> 
    { 
     internal Node() { } 
     public T Item { get; internal set; } 
     public int Level { get; internal set; } 
     public Node<T> Parent { get; internal set; } 
     public IList<Node<T>> Children { get; internal set; } 
    } 

    public static IEnumerable<Node<T>> ToHierarchy<T>(
     this IEnumerable<T> source, 
     Func<T, bool> startWith, 
     Func<T, T, bool> connectBy) 
    { 
     if (source == null) throw new ArgumentNullException("source"); 
     if (startWith == null) throw new ArgumentNullException("startWith"); 
     if (connectBy == null) throw new ArgumentNullException("connectBy"); 
     return source.ToHierarchy(startWith, connectBy, null); 
    } 

    private static IEnumerable<Node<T>> ToHierarchy<T>(
     this IEnumerable<T> source, 
     Func<T, bool> startWith, 
     Func<T, T, bool> connectBy, 
     Node<T> parent) 
    { 
     int level = (parent == null ? 0 : parent.Level + 1); 

     var roots = from item in source 
        where startWith(item) 
        select item; 
     foreach (T value in roots) 
     { 
      var children = new List<Node<T>>(); 
      var newNode = new Node<T> 
      { 
       Level = level, 
       Parent = parent, 
       Item = value, 
       Children = children.AsReadOnly() 
      }; 

      T tmpValue = value; 
      children.AddRange(source.ToHierarchy(possibleSub => connectBy(tmpValue, possibleSub), connectBy, newNode)); 

      yield return newNode; 
     } 
    } 

Nel caso di un DataTable come origine, è possibile utilizzarlo in questo modo:

var hierarchy = 
    sourceTable.AsEnumerable() 
       .ToHierarchy(row => row.IsNull("ParentKey"), 
          (parent, child) => parent.Field<int>("Key") == 
               child.Field<int>("ParentKey")) 

(hierarchy è un IEnumerable<Node<DataRow>>)

Si noti che se si def Ine la relazione genitore-figlio nello stesso DataTable, è già avere una struttura ad albero ... è sufficiente selezionare le radici (elementi senza genitore).

+0

I am ottenendo errori di compilazione durante l'utilizzo di questo codice. Ho aggiornato la mia domanda con il tuo suggerimento – SharpCoder

+0

@Brown_Dynamite, il metodo ToHierarchy non è un membro del Nodo , è un metodo di estensione quindi dovrebbe essere in una classe statica –

+0

anche dopo aver aggiunto tali metodi nella classe statica, sto ricevendo lo stesso errore :( – SharpCoder