2013-03-08 11 views
7

Attualmente stiamo facendo questo loop attraverso ogni valore della lista e dizionario:coverting Elenco dei dizionario per DataTable

private DataTable ChangeToDictionary(List<Dictionary<string,int>> list) 
     { 
      DataTable datatTableReturn = new DataTable(); 

      if (list.Count() > 0) 
      { 
       Dictionary<string, int> haeders = list.ElementAt(0); 
       foreach (var colHead in haeders) 
       { 
        datatTableReturn.Columns.Add(colHead.Key); 
       } 
      } 

      foreach (var row in list) 
      { 
       DataRow dataRow = datatTableReturn.NewRow(); 
       foreach (var col in row) 
       { 

        dataRow[col.Key] = col.Value; 
       } 
       datatTableReturn.Rows.Add(dataRow); 
      } 
      return datatTableReturn; 

     } 

ma c'è un modo migliore? Fare il giro tante volte non è bello

+0

Come cosa? Qualunque altro approccio alla fine dovrebbe passare sopra tutti i dati c.q. loop sopra i record. Non vedo il vero problema che stai avendo. Non ti piace il codice sopra? – Bazzz

+0

Funziona, ma come detto c'è un modo migliore e affidabile – Simsons

+3

Perché convertire in DataTable in primo luogo? – Jodrell

risposta

4

Velocità, eleganza e riusabilità non vanno insieme. Scegli sempre quello più importante e cerca di bilanciare gli altri due.

Più veloce è il codice, più brutto è. Più bello è, meno riutilizzabile.

Ecco un esempio di soluzione "elegante", ma che con esso non è molto leggibile.

private static DataTable ToDictionary(List<Dictionary<string, int>> list) 
{ 
    DataTable result = new DataTable(); 
    if (list.Count == 0) 
     return result; 

    result.Columns.AddRange(
     list.First().Select(r => new DataColumn(r.Key)).ToArray() 
    ); 

    list.ForEach(r => result.Rows.Add(r.Select(c => c.Value).Cast<object>().ToArray())); 

    return result; 
} 
+0

si itera la prima riga due volte. – Jodrell

+0

e 'int' è già un' oggetto' – Jodrell

+0

Non esiste una relazione fissa tra prestazioni e leggibilità. Il codice veloce può essere un codice leggibile. La bruttezza è puramente soggettiva. – Jodrell

1

Che ne dici di qualcosa come il seguente codice?

Buono, perché itera ogni riga esattamente una volta. Dovrebbe essere piuttosto veloce, ho incluso delle ovvie eccezioni per rendere il codice più sicuro.

private static DataTable DictionariesToDataTable<T>(
     IEnumerable<IDictionary<string, T>> source) 
{ 
    if (source == null) 
    { 
     return null; 
    } 

    var result = new DataTable(); 
    using (var e = source.GetEnumerator()) 
    { 
     if (!e.MoveNext()) 
     { 
      return result; 
     } 

     if (e.Current.Keys.Length == 0) 
     { 
      throw new InvalidOperationException(); 
     } 

     var length = e.Current.Keys.Length; 

     result.Columns.AddRange(
      e.Current.Keys.Select(k => new DataColumn(k, typeof(T))).ToArray()); 

     do 
     { 
      if (e.Current.Values.Length != length) 
      { 
       throw new InvalidOperationException(); 
      } 

      result.Rows.Add(e.Current.Values); 
     } 
     while (e.MoveNext()); 

     return result; 
    } 
} 
+0

Non stai eliminando l'enumeratore. – Romoku

+0

@Romoku, vero, risolto. – Jodrell

8

Le risposte precedenti non risolvono il problema del dizionario con più di 1 riga. Questa soluzione risolve il problema.

static DataTable ToDataTable(List<Dictionary<string, int>> list) 
{ 
    DataTable result = new DataTable(); 
    if (list.Count == 0) 
     return result; 

    var columnNames = list.SelectMany(dict=>dict.Keys).Distinct(); 
    result.Columns.AddRange(columnNames.Select(c=>new DataColumn(c)).ToArray()); 
    foreach (Dictionary<string,int> item in list) 
    { 
     var row = result.NewRow(); 
     foreach (var key in item.Keys) 
     { 
      row[key] = item[key]; 
     } 

     result.Rows.Add(row); 
    } 

    return result; 
} 

static void Main(string[] args) 
{ 
    List<Dictionary<string, int>> it = new List<Dictionary<string, int>>(); 
    Dictionary<string, int> dict = new Dictionary<string, int>(); 
    dict.Add("a", 1); 
    dict.Add("b", 2); 
    dict.Add("c", 3); 
    it.Add(dict); 
    dict = new Dictionary<string, int>(); 
    dict.Add("bob", 34); 
    dict.Add("tom", 37); 
    it.Add(dict); 
    dict = new Dictionary<string, int>(); 
    dict.Add("Yip Yip", 8); 
    dict.Add("Yap Yap", 9); 
    it.Add(dict); 

    DataTable table = ToDictionary(it); 
    foreach (DataColumn col in table.Columns) 
     Console.Write("{0}\t", col.ColumnName); 
    Console.WriteLine(); 
    foreach (DataRow row in table.Rows) 
    { 
     foreach (DataColumn column in table.Columns) 
      Console.Write("{0}\t", row[column].ToString()); 
     Console.WriteLine(); 
    } 
    Console.ReadLine(); 

} 

E l'uscita sembra ...

a  b  c  bob  tom  Yip Yip Yap Yap 
1  2  3 
         34  37 
             8  9 
+0

l'output non corrisponde al tuo input. – Jodrell

+1

(facepalm) oops. hai ragione. Ho usato per errore l'iteratore sbagliato. Modificato con correzione. –

+0

Questo è stato un risparmio di tempo. Complimenti! –

1

Prova questa:

private DataTable GetDataTableFromDictionaries<T>(List<Dictionary<string, T>> list) 
    { 
     DataTable dataTable = new DataTable(); 

     if (list == null || !list.Any()) return dataTable; 

     foreach (var column in list.First().Select(c => new DataColumn(c.Key, typeof(T)))) 
     { 
      dataTable.Columns.Add(column); 
     } 

     foreach (var row in list.Select(
      r => 
       { 
        var dataRow = dataTable.NewRow(); 
        r.ToList().ForEach(c => dataRow.SetField(c.Key, c.Value)); 
        return dataRow; 
       })) 
     { 
      dataTable.Rows.Add(row); 
     } 

     return dataTable; 
    } 
0

provare la mia soluzione, sembra molto pulito per me:

private DataTable DictonarysToDataTable(List<Dictionary<string, int>> list) 
    { 
     DataTable table = new DataTable(); 

     foreach (Dictionary<string,string> dict in list)  //for every dictonary in the list .. 
     { 
      foreach (KeyValuePair<string,int> entry in dict) //for every entry in every dict 
      { 
       if (!myTable.Columns.Contains(entry.Key.ToString()))//if it doesn't exist yet 
       { 
        myTable.Columns.Add(entry.Key);     //add all it's keys as columns to the table 
       } 
      } 
      table.Rows.Add(dict.Values.ToArray());    //add the the Values of every dict in the list as a new row 
     } 

     return table; 
    } 

Edit : Oh Snap, funziona solo per un Dicti onary .. non ci ho pensato. Ma maybie è possibile modificarlo a lavorare per un elenco di dictionarys ..

0

dare una prova si prega di

 DataTable table = new DataTable(); 

     foreach (IDictionary<string, object> row in DeviceTypeReport) 
     { 
      foreach (KeyValuePair<string, object> entry in row) 
      { 
       if (!table.Columns.Contains(entry.Key.ToString())) 
       { 
        table.Columns.Add(entry.Key); 
       } 
      } 
      table.Rows.Add(row.Values.ToArray()); 
     }