Конвертировать столбцы DataTable в типизированный IEnumerable[]
Как преобразовать столбцы DataTable в IEnumerable[], который необходим для создания фрейма данных в R.NET
У меня есть следующий код:
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);
Я получаю следующее исключение:
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();
ОБНОВИТЬ
Пока у меня есть отвратительное решение, может ли оно быть сделано лучше?
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));
}
}
3 ответа
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;
}
Это?
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;
}
Вот как получить объект DataTable в List (который реализует 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;
}
}