初始化类的功能方法

时间:2015-09-09 09:37:10

标签: f# functional-programming

我是F#的新手,所以我热衷于尝试以更实用的方式处理问题(而不是我习惯的命令式思维)。

对于这个问题,我正在从Excel中读取数据,其中包含大约6000行数据,包含多个字段(年龄,性别,性别等)。

我正在使用一个类来存储这些数据点 - 摘录如下:

type datastore(array:obj[,], row)=
    let id=array.[row,1]:?> string;
    let gender=array.[row,2] :?> string;
    let sex = array.[row,3] :?> string;
    //...continues for a number of other cases

我目前正在使用以下代码初始化这些类,这些代码工作正常,但这是一种必要的方法:

let DataPoints = 
    let DataInput = //function to read data in from Excel
    [for i in DataInput.GetLowerBound(0) .. DataInput.GetUpperBound(0) -> 
        new datastore(DataInput,i)]

我的问题是,我怎样才能以更实用的方式做到这一点?

我尝试过以下操作(不起作用:给出的错误只是'因错误而停止')。

let num = DataInput.GetUpperBound(0)
let MPs3 = Array.init  num (fun x -> new datastore(DataInput,x))

我还查看了以下链接,这些链接似乎没有完全帮助。

Array initialization in F#

How to define a record field as an array in f#?

2 个答案:

答案 0 :(得分:3)

函数式编程是每个人都有自己私有定义的事情之一。如果你问我,两个突出的品质是:

  • 根据类型思考事物(称之为类型驱动,类型优先编程或其他),
  • 将您的逻辑视为由可组合步骤构成的数据转换管道。

所以,如果我遇到像你这样的问题,我首先要定义一个强类型的数据表示。记录比存储“哑”数据的类更适合,所以这就是我使用的:

type DataPoint = 
    {
        Id:     string
        Gender: GenderType
        Sex:    SexType
    }
    static member FromRow(row: obj []) = 
        {
            Id     = row.[0] :?> string
            Gender = GenderType.Parse <| (row.[1] :?> string)
            Sex    = SexType.Parse <| (row.[2] :?> string)
        } 

为了正确表示,GenderSex应该是具有Parse函数而非字符串的歧视联盟,但我会将它们定义为读者的练习;)

一旦你有办法将数组中的一行转换为DataPoint,你需要实际获取行。为此,让我们将您从Excel获得的2d数组切割成一系列行。没有标准功能可以做到这一点,但它应该大致如下:

module Array2D = 
    let intoRows (arr: obj[,]) : seq<obj []> = 
        seq { for x in 0 .. Array2D.length1 arr - 1 do
                  yield [| for y in 0 .. Array2D.length2 arr - 1 -> arr.[x, y] |]}

有了这个,我们拥有了我们需要的一切,所以现在把它们放在一个管道中:

let dataPoints = 
    let input = //function to read data in from Excel
    input
    |> Array2D.intoRows
    |> Seq.map DataPoint.FromRow
    |> Array.ofSeq

这样可以很容易地看到发生了什么。您可以在每个步骤轻松剖析数据,并且扩展代码很简单。例如,如果您想将每个记录转换为一个类(例如视图模型),那么这只是另一个map步骤。

答案 1 :(得分:2)

我不会把它作为&#34;更少,或更多功能&#34;。第二个代码段中的DataPoints是由{#{3}}机制初始化的datastore列表

如果您希望DataPoints成为由标准库函数list comprehension初始化的datastore值的数组,则对应的代码可能看起来像

let DataPoints =
   let (il,ih) = (DataInput.GetLowerBound(0),DataInput.GetUpperBound(0)) in
   Array.init (ih - il + 1) (fun x -> new datastore(DataInput, x + il))

为了从Array.init0采用给定的number of elements - 1元素索引处理,从DataInput.GetLowerBound(0)DataInput.GetUpperBound(0) - DataInput.GetLowerBound(0)采用所需的元素索引。

但这两种方法都是用于生成元素序列的函数式编程理解形式。