2016-11-29 4 views
1

Как конвертировать DataTable столбцы IEnumerable [], которая требуется для создания кадра данных в R.NETПреобразовать DataTable столбцы набраны IEnumerable []

У меня есть следующий код:

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 получаю следующее исключение:

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 имеет столбцы различных типов, и я не знаю, какие типы, так что я не могу сделать, как в этом примере с double:

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

UPDATE

До сих пор я некрасивое решение, это может быть сделано лучше?

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)); 
    }     
} 

ответ

0

Вот как получить DataTable объект в список (который реализует IEnumerable) объекта, который представляет структуру столбца таблицы, используя динамический тип и метод расширения:

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

Благодарим за ответ, но это решение работает только тогда, когда известна структура таблицы данных. Мне нужно универсальное решение, не зная структуры данных. –

+0

Ah ok Я понимаю сейчас - я отредактировал свой ответ, чтобы показать, как это можно сделать. –

+0

Обратите внимание, что список типов динамиков ia не совпадает с тем же объявлением IEnumerable [], которое является, например, массив массива. Это необходимо для 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; 
} 

Это?

+0

Добро пожаловать в SO. Пожалуйста, предоставьте какой-либо контекст или объяснение вашего ответа. Только код не соответствует стандартам качества. См. 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; 
} 
Смежные вопросы