将DataTable转换为Double类型的数组

4
我有一个DataTable对象作为SQL读取的结果。一个典型的例子包含100行和16列。我需要多次迭代表格,提取值进行计算(应用于机器学习梯度下降)。 我正在尝试加速计算,并避免每次使用时都要转换从DataTable读取的值。是否有一种方法可以通过仅转换整个DataTable对象来创建新的2D索引数组,从而消除调用Convert.ToDouble 1000x100x16=1,600,000次的需要。理想情况下,为了代码可读性,我希望保留将数据引用为["colname",row]的方式。

目前的实现:

for(i=0;i<1000;i++)
  foreach (DataRow row in dt.Rows)
    calculation = Convert.ToDouble(row["col1"])....

你能否将它们存储为数据库中的双精度吗? - Gilad Green
你确定需要转换什么吗?如果值已经以double类型加载,你只需要进行强制转换——甚至可能不需要。强类型数据行使用其实际类型公开值。 - Panagiotis Kanavos
甚至更好的方法是使用 LinQ 或在数据集上使用 LinQ,将您的数据作为 Iqueryable<customObject> 获取。 - Drag and Drop
Gilad:是的,数据在数据库中存储为Double,但当放入DataTable对象时,所有内容都会转换为对象。 Steve:是的,我可以循环遍历行,只是通常这里有人知道更简洁的方法。 Panagiotis:是的,强制转换似乎有效(呃!) AndyJ:我不会每次获取表格,所以不知道我是否可以使用相同的DataReader进行迭代,是否有指针重置? Pierre:我会查看Linq。 - gregm
1
@gregm DataReader是与数据库的实时连接,您应该从中读取数据,然后尽快关闭它,以便其他访问服务器的用户可以使用该连接。如果您想保留数据,则将其存储在内存中并使用它。您可能会说“但这就是datatable所做的事情”,您是正确的...但它的效率非常低下。 - user310988
显示剩余7条评论
4个回答

3

使用:

using System;
using System.Linq;
using System.Data;    
DataTable db = <some table>;
double[][] arrayOfDoubles = db.AsEnumerable().Select(x => new [] { Convert.ToDouble(x["SomeColumn"]), Convert.ToDouble(x["SomeColumn"]), ... }).ToArray();

不要忘记检查DbNull


现在你有一个 EnumerableRowCollection<double>,这不是 OP 要求的二维数组。 - Nino
@Nino 感谢您的提醒,我已经进行了修改。 - Zoran Basic

2
你需要一个自定义对象来保存每行单元格的值:
public class Dto // you can chose better name for dto class
{
   public double Column1 { get; set; }
   // other properties go here
}

接下来将您的数据表转换为这些对象的字典,使用行索引作为键:

var map = dt.AsEnumerable()
            .Select((r,i) => new { 
                RowIndex = i,
                Value = new Dto { 
                    Column1 = r.Field<double>("col1") 
                    // parse other columns here
                }                    
             }))
            .ToDictionary(x => x.RowIndex, x => x.Value);

之后您将能够引用列的值,如下:

map[rowIndex].Column1

1

dt.Rows.Select(r => Convert.ToDouble(r["col1"])).ToArray()会返回一个double数组,并且与原始的DataTable具有相同的顺序。你无需存储对源行的引用,因为你正在检查的索引本身就是原始行的索引。

请注意,您需要导入System.Linq并添加对System.Data.DatasetExtensions的引用才能使此方法起作用。

在循环外执行一次,然后在生成的数组上运行您的循环:

var arr = dt.Rows.Select(r => Convert.ToDouble(r["col1"])).ToArray();

for(i=0;i<1000;i++)
    for(j=0;j<arr.Length;j++)
    {
        calculation = arr[j] /* your operation here */;
        //dt.Rows[j] is also available if needed at any time
    }   

0
您可以创建一个类来保存您的图形,甚至可以在其中放置一些计算。
List<MyCalculationOject> calculationOjects = dt.AsEnumerable().Select(
    row => new MyCalculationOject {
        Figure1 = row.Field<double>("figure1_Col"), 
        Figure2 = row.Field<double>("figure2_Col"), 
        ....})).ToList();

public class MyCalculationOject
{
    public double Figure1 {get;set;}
    ...

    public double SomeBasicCalculation() {..}
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接