2016-11-29 1 views
1

Comment convertir des colonnes DataTable IEnumerable [] qui est nécessaire pour créer une trame de données dans R.NETcolonnes DataTable dactylographié IEnumerable []

je le code suivant:

DataTable dt = CreateDateTable(); 
REngine e = REngine.GetInstance();      
IEnumerable[] columns = new IEnumerable[dt.Columns.Count];     
string[] columnNames = dt.Columns.Cast<DataColumn>() 
         .Select(x => x.ColumnName) 
         .ToArray(); 

for(int i=0; i<dt.Columns.Count; i++) 
    //This is the place where I am stuck. How to convert column to base type array instead of object array 
    columns[i] = dt.Rows.Cast<DataRow>().Select(row => row[i]).ToArray(); 

DataFrame df = e.CreateDataFrame(columns: columns, 
columnNames: columnNames, 
stringsAsFactors: false); 

I obtenir l'exception suivante:

Test 'XXX.ReadResultsTest' failed: System.NotSupportedException : Cannot convert type System.Object[] to an R vector 
     w RDotNet.REngineExtension.ToVector(REngine engine, IEnumerable values) 
     w System.Array.ConvertAll[TInput,TOutput](TInput[] array, Converter`2 converter) 
     w RDotNet.REngineExtension.CreateDataFrame(REngine engine, IEnumerable[] columns, String[] columnNames, String[] rowNames, Boolean checkRows, Boolean checkNames, Boolean stringsAsFactors) 

DataTable a des colonnes de types différents et je ne sais pas quels sont les types, donc je ne peux pas faire comme dans cet exemple avec double:

for (int i = 0; i < dt.Columns.Count; i++) 
     columns[i] = dt.Rows.Cast<DataRow>().Select(row => row.Field<double>(i)).ToArray(); 

MISE À JOUR

Jusqu'à présent, j'ai une solution laide, peut-il être mieux fait?

for (int i = 0; i < dt.Columns.Count; i++) 
{ 
    switch (Type.GetTypeCode(dt.Columns[i].DataType)) 
    { 
     case TypeCode.String: 
      columns[i] = dt.Rows.Cast<DataRow>().Select(row => row.Field<string>(i)).ToArray(); 
      break; 

     case TypeCode.Double: 
      columns[i] = dt.Rows.Cast<DataRow>().Select(row => row.Field<double>(i)).ToArray(); 
      break; 

     case TypeCode.Int32: 
      columns[i] = dt.Rows.Cast<DataRow>().Select(row => row.Field<int>(i)).ToArray(); 
      break; 

     case TypeCode.Int64: 
      columns[i] = dt.Rows.Cast<DataRow>().Select(row => row.Field<long>(i)).ToArray(); 
      break; 

     default: 
      //columns[i] = dt.Rows.Cast<DataRow>().Select(row => row[i]).ToArray(); 
      throw new InvalidOperationException(String.Format("Type {0} is not supported", dt.Columns[i].DataType.Name)); 
    }     
} 

Répondre

0

Voici comment obtenir un objet DataTable dans une liste (qui implémente IEnumerable) d'un objet qui représente la structure de la colonne de table à l'aide d'un type dynamique et une méthode d'extension:

class Program 
{ 
    static void Main() 
    { 
     var dt = new DataTable(); 
     //populate dt... 

     List<dynamic> dataTableList= dt.DataTableToList(); 
    } 
} 

public static class DataTableExtensions 
{ 
    public static List<dynamic> DataTableToList(this DataTable dt) 
    { 
     var list= new List<dynamic>(); 
     foreach (DataRow row in dt.Rows) 
     { 
      dynamic d = new ExpandoObject(); 
      list.Add(d); 
      foreach (DataColumn column in dt.Columns) 
      { 
       var dic = (IDictionary<string, object>)d; 
       dic[column.ColumnName] = row[column]; 
      } 
     } 

     return list; 
    } 
} 
+1

Merci pour la réponse, mais cette solution ne fonctionne que lorsque la structure de la table de données est connue. J'ai besoin d'une solution universelle, sans connaître la structure de datatable. –

+0

Ah ok je comprends maintenant - j'ai édité ma réponse pour montrer comment cela peut être accompli. –

+0

Veuillez noter que la liste des types de dynamic ne comprend pas la même annonce IEnumerable [] qui est par exemple. un tableau de tableau. Ceci est nécessaire pour RDotNet –

1
public DataFrame DataTableToDataFrame(string name, DataTable dt) 
{ 
    DataFrame dataFrame = null; 

    IEnumerable[] columns = new IEnumerable[dt.Columns.Count]; 
    string[] columnNames = dt.Columns.Cast<DataColumn>() 
          .Select(x => x.ColumnName) 
          .ToArray(); 

    for (int i = 0; i < dt.Columns.Count; i++) 
    { 
     switch (Type.GetTypeCode(dt.Columns[i].DataType)) 
     { 
      case TypeCode.String: 
       columns[i] = dt.Rows.Cast<DataRow>().Select(row => row.Field<string>(i)).ToArray(); 
       break; 

      case TypeCode.Double: 
       columns[i] = dt.Rows.Cast<DataRow>().Select(row => row.Field<double>(i)).ToArray(); 
       break; 

      case TypeCode.Int32: 
       columns[i] = dt.Rows.Cast<DataRow>().Select(row => row.Field<int>(i)).ToArray(); 
       break; 

      case TypeCode.Int64: 
      case TypeCode.Decimal: 
       IEnumerable array = dt.Rows.Cast<DataRow>().Select(row => row.Field<object>(i)).ToArray(); 

       //columns[i] = dt.Rows.Cast<DataRow>().Select(row => row.Field<long>(i)).ToArray(); 
       //columns[i] = dt.Rows.Cast<DataRow>().Select(row => row.Field<decimal>(i)).ToArray(); 

       columns[i] = ListToIenumerable(array); 
       break; 

      default: 
       columns[i] = dt.Rows.Cast<DataRow>().Select(row => row[i]).ToArray(); 
       //throw new InvalidOperationException(String.Format("Type {0} is not supported", dt.Columns[i].DataType.Name)); 
       break; 
     } 
    } 

    dataFrame = REngine.CreateDataFrame(columns: columns, columnNames: columnNames, stringsAsFactors: false); 
    REngine.SetSymbol(name, dataFrame); 

    return dataFrame; 
} 

Ceci est?

+0

Bienvenue dans SO. Veuillez fournir un contexte ou une explication à votre réponse. Le code seulement ne répond pas aux normes de qualité. Voir http://stackoverflow.com/help/how-to-answer –

0
public IEnumerable<int> ListToIenumerable(IEnumerable enumerable) 
{ 
    List<int> list = new List<int>(); 

    foreach (object obj in enumerable) 
    { 
     list.Add(Convert.ToInt32(obj.ToString())); 
    } 

    IEnumerable<int> returnValue = list.ToArray(); 

    return returnValue; 
}