我是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))
我还查看了以下链接,这些链接似乎没有完全帮助。
答案 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)
}
为了正确表示,Gender
和Sex
应该是具有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.init
到0
采用给定的number of elements - 1
元素索引处理,从DataInput.GetLowerBound(0)
到DataInput.GetUpperBound(0) - DataInput.GetLowerBound(0)
采用所需的元素索引。
但这两种方法都是用于生成元素序列的函数式编程理解形式。