传递一个.NET数据表到MATLAB [英] Passing a .NET Datatable to MATLAB

查看:796
本文介绍了传递一个.NET数据表到MATLAB的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我建的,用来分析由一个独立的.NET应用程序,我还建设维护的数据Matlab的组件的接口层。我想连载一个.NET数据表作为数字数组传递给MATLAB组件(如一个更广义的序列化程序的一部分)。

I'm building an interface layer for a Matlab component which is used to analyse data maintained by a separate .NET application which I am also building. I'm trying to serialise a .NET datatable as a numeric array to be passed to the MATLAB component (as part of a more generalised serialisation routine).

到目前为止,我已经相当成功与传递的数字数据的表,但试图添加数据类型的列时,我遇到了障碍的DateTime 。我一直在做的到现在馅是从数据表的值转换为双阵列,因为MATLAB只有真正关心双打,然后做直投至 MWNumericArray ,它本质上是一个矩阵。

So far, I've been reasonably successful with passing tables of numeric data but I've hit a snag when trying to add a column of datatype DateTime. What I've been doing up to now is stuffing the values from the DataTable into a double array, because MATLAB only really cares about doubles, and then doing a straight cast to a MWNumericArray, which is essentially a matrix.

下面是目前的code;

Here's the current code;

else if (sourceType == typeof(DataTable))
{
    DataTable dtSource = source as DataTable;
    var rowIdentifiers = new string[dtSource.Rows.Count];               
    // I know this looks silly but we need the index of each item
    // in the string array as the actual value in the array as well
    for (int i = 0; i < dtSource.Rows.Count; i++)
    {
        rowIdentifiers[i] = i.ToString();
    }
    // convenience vars
    int rowCount = dtSource.Rows.Count;
    int colCount = dtSource.Columns.Count;
    double[,] values = new double[rowCount, colCount];

    // For each row 
    for (int rownum = 0; rownum < rowCount; rownum++)
    {
        // for each column
        for (int colnum = 0; colnum < colCount; colnum++)
        {
            // ASSUMPTION. value is a double
            values[rownum, colnum] = Conversion.ConvertToDouble(dtSource.Rows[rownum][colnum]);
        }
    }
    return (MWNumericArray)values;
}

Conversion.ConvertToDouble 是我自己的日常迎合空值,为DBNull并返回double.NaN,又因为Matlab的将所有NULLS为NaN的。

Conversion.ConvertToDouble is my own routine which caters for NULLS, DBNull and returns double.NaN, again because Matlab treats all NULLS as NaNs.

所以这里的东西;有谁知道的MATLAB数据类型,让我通过在一个连续阵列具有多个数据类型?唯一的解决方法,我可以设想涉及使用 MWStructArray MWStructArrays ,但这似乎哈克和我不知道以及它如何将工作在MATLAB code,所以我想尝试找到一个更好的解决方案,如果我能。我看了一下使用 MWCellArray ,但它给了我一个编译错误,当我尝试实例化。

So here's the thing; Does anyone know of a MATLAB datatype that would allow me to pass in a contiguous array with multiple datatypes? The only workaround I can conceive of involves using a MWStructArray of MWStructArrays, but that seems hacky and I'm not sure how well it would work in the MATLAB code, so I'd like to try to find a more elegant solution if I can. I've had a look at using an MWCellArray, but it gives me a compile error when I try to instantiate it.

我希望能够做这样的事情;

I'd like to be able to do something like;

object[,] values = new object[rowCount, colCount];
// fill loosely-typed object array
return (MWCellArray)values;

但正如我所说,我得到一个编译错误这一点,也与传递一个对象数组构造函数。

But as I said, I get a compile error with this, also with passing an object array to the constructor.

如果我错过了什么愚蠢的道歉。我做了一些谷歌搜索,但基于Matlab信息.NET接口似乎有点轻,所以这就是为什么我把它贴在这里。

Apologies if I have missed anything silly. I've done some Googling, but information on Matlab to .NET interfaces seems a little light, so that is why I posted it here.

在此先感谢。

感谢大家的建议。

原来,我们的具体实施最快捷,最有效的方式是把日期时间转换为在SQL code int类型。

Turns out that the quickest and most efficient way for our specific implementation was to convert the Datetime to an int in the SQL code.

不过,其他的方法,我会建议使用MWCharArray方法。它使用最少做文章,而事实证明,我只是做错了 - 你不能把它当作另一种MWArray类型,因为它当然是专门用来对付你需要遍历它的多个数据类型,贴在MWNumerics或当您去任何需要你的想象。有一点需要注意的是,MWArrays是基于1的,不是基于0的。那一个不断追赶我了。

However, of the other approaches, I would recommend using the MWCharArray approach. It uses the least fuss, and it turns out I was just doing it wrong - you can't treat it like another MWArray type, as it is of course designed to deal with multiple datatypes you need to iterate over it, sticking in MWNumerics or whatever takes your fancy as you go. One thing to be aware of is that MWArrays are 1-based, not 0-based. That one keeps catching me out.

我将进入更详细的讨论后的今天,当我有时间,但现在我不知道。谢谢大家再次对你有所帮助。

I'll go into a more detailed discussion later today when I have the time, but right now I don't. Thanks everyone once more for your help.

推荐答案

随着 @马特的建议的意见,如果要存储不同数据类型(数字,字符串,结构,等...),你应该使用电池阵列由该暴露相当于托管API,即<一href="http://www.mathworks.com/help/toolbox/dotnetbuilder/MWArrayAPI/HTML/MathWorks.MATLAB.NET.Arrays.MWCellArray.html">MWCellArray类。

As @Matt suggested in the comments, if you want to store different datatypes (numeric, strings, structs, etc...), you should use the equivalent of cell-arrays exposed by this managed API, namely the MWCellArray class.

要说明这一点,我实现了一个简单的.NET程序集。它暴露了MATLAB函数接收一个单元阵列(记录从数据库表),并简单地打印它们。此功能会从我们的C#应用​​程序,它会生成一个样本数据表被调用,将其转换成 MWCellArray (填入表项的细胞通过细胞)。

To illustrate, I implemented a simple .NET assembly. It exposes a MATLAB function that receives a cell-array (records from a database table), and simply prints them. This function would be called from our C# application, which generates a sample DataTable, and convert it into a MWCellArray (fill table entries cell-by-cell).

关键是要映射的 MWArray 派生类包含在数据表来支持的类型的对象。这里都是我用(检查<一href="http://www.mathworks.com/help/toolbox/dotnetbuilder/MWArrayAPI/HTML/index.html">documentation有关完整列表):

The trick is to map the objects contained in the DataTable to the supported types by the MWArray-derived classes. Here are the ones I used (check the documentation for a complete list):

.NET native type          MWArray classes
------------------------------------------
double,float,int,..       MWNumericArray
string                    MWCharArray
DateTime                  MWNumericArray       (using Ticks property)

有关日期/时间数据的说明:在.NET中,的System.DateTime EX presses日期和时间为:

A note about the date/time data: in .NET, the System.DateTime expresses date and time as:

自一月份以来已经过去了100纳秒间隔数   1,0001在00:00:00.000

the number of 100-nanosecond intervals that have elapsed since January 1, 0001 at 00:00:00.000

而在MATLAB,这就是 DATENUM 功能不得不说:

while in MATLAB, this is what the DATENUM function has to say:

日期以一串数字再presents全和分数   从一个特定的日期和时间,其中datenum('扬1-0000天   00:00:00)返回1号

A serial date number represents the whole and fractional number of days from a specific date and time, where datenum('Jan-1-0000 00:00:00') returns the number 1

由于这个原因,我在C#应用程序转换的的DateTime 蜱,以匹配序列日期数字的MATLAB定义写了两个辅助功能。

For this reason, I wrote two helper functions in the C# application to convert the DateTime "ticks" to match the MATLAB definition of serial date numbers.

首先,考虑这个简单的MATLAB函数。它预计将收到包含表数据的numRos按数numCols cellarray。在我的例子中,列有:名称(字符串),价格(双),日期(日期时间)

First, consider this simple MATLAB function. It expects to receive a numRos-by-numCols cellarray containing the table data. In my example, the columns are: Name (string), Price (double), Date (DateTime)

function [] = my_cell_function(C)
    names = C(:,1);
    price = cell2mat(C(:,2));
    dt = datevec( cell2mat(C(:,3)) );

    disp(names)
    disp(price)
    disp(dt)
end

使用部署工具从MATLAB生成器NE,我们所建立的上述作为.NET部件。接下来,我们创建一个C#控制台应用程序,然后添加一个引用 MWArray.dll 组装,除了上述生成一个。这是我使用的程序:

Using deploytool from MATLAB Builder NE, we build the above as a .NET assembly. Next, we create a C# console application, then add a reference to the MWArray.dll assembly, in addition to the above generated one. This is the program I am using:

using System;
using System.Data;
using MathWorks.MATLAB.NET.Utility;  // MWArray.dll
using MathWorks.MATLAB.NET.Arrays;   // MWArray.dll
using CellExample;                   // CellExample.dll assembly created

namespace CellExampleTest
{
    class Program
    {
        static void Main(string[] args)
        {
            // get data table
            DataTable table = getData();

            // create the MWCellArray
            int numRows = table.Rows.Count;
            int numCols = table.Columns.Count;
            MWCellArray cell = new MWCellArray(numRows, numCols);   // one-based indices

            // fill it cell-by-cell
            for (int r = 0; r < numRows; r++)
            {
                for (int c = 0; c < numCols; c++)
                {
                    // fill based on type
                    Type t = table.Columns[c].DataType;
                    if (t == typeof(DateTime))
                    {
                        //cell[r+1,c+1] = new MWNumericArray( convertToMATLABDateNum((DateTime)table.Rows[r][c]) );
                        cell[r + 1, c + 1] = convertToMATLABDateNum((DateTime)table.Rows[r][c]);
                    }
                    else if (t == typeof(string))
                    {
                        //cell[r+1,c+1] = new MWCharArray( (string)table.Rows[r][c] );
                        cell[r + 1, c + 1] = (string)table.Rows[r][c];
                    }
                    else
                    {
                        //cell[r+1,c+1] = new MWNumericArray( (double)table.Rows[r][c] );
                        cell[r + 1, c + 1] = (double)table.Rows[r][c];
                    }
                }
            }

            // call MATLAB function
            CellClass obj = new CellClass();
            obj.my_cell_function(cell);

            // Wait for user to exit application
            Console.ReadKey();
        }

        // DateTime <-> datenum helper functions
        static double convertToMATLABDateNum(DateTime dt)
        {
            return (double)dt.AddYears(1).AddDays(1).Ticks / (10000000L * 3600L * 24L);
        }
        static DateTime convertFromMATLABDateNum(double datenum)
        {
            DateTime dt = new DateTime((long)(datenum * (10000000L * 3600L * 24L)));
            return dt.AddYears(-1).AddDays(-1);
        }

        // return DataTable data
        static DataTable getData()
        {
            DataTable table = new DataTable();
            table.Columns.Add("Name", typeof(string));
            table.Columns.Add("Price", typeof(double));
            table.Columns.Add("Date", typeof(DateTime));

            table.Rows.Add("Amro", 25, DateTime.Now);
            table.Rows.Add("Bob", 10, DateTime.Now.AddDays(1));
            table.Rows.Add("Alice", 50, DateTime.Now.AddDays(2));

            return table;
        }
    }
}

本C#程序中所返回的编译MATLAB函数的输出:

The output of this C# program as returned by the compiled MATLAB function:

'Amro'
'Bob'
'Alice'

25
10
50

     2011            9           26           20           13       8.3906
     2011            9           27           20           13       8.3906
     2011            9           28           20           13       8.3906

这篇关于传递一个.NET数据表到MATLAB的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆