如何将记录转换为元组?

时间:2018-05-31 00:15:41

标签: f# type-providers

我使用CSV类型提供程序,它使用元组作为所有底层数据。我的问题是我遇到了包含大量列的csv文件,并发现围绕操作该大小的数据构建基础结构相当麻烦。如何构建一个只更新列的特定子集而不必创建大型模式匹配语句的函数?请参阅下面的代码示例。

// I want to generate lots of sample data for the first three columns
// And I would like to avoid creating giant record types in order to
// do this task as the csv's are always changing and the records would
// have to change as well
type CumbersomeCSVRow = // 17 fields now, but imagine 212
    string * string * string * Option<int> * string * 
    Option<int> * string * string * string * string * 
    string * string * Option<float> * string * 
    Option<float> * Option<float> * string

// Here is a sample row of data
let sampleCumbersomeRow : CumbersomeCSVRow = 
    ("First","Second","Third",Some(52),"MSCI",None,"B74A123","",
     "Airlines","Transportation","","",Some(1.04293),"Updated",
     Some(0.95),Some(56.7423),"Measured")

// Record type of the sample data that I want to 'insert' into the cumbersome data type
type FirstThreeStrings = 
    { First : string; Second : string; Third : string}

// and some instances of the new data
let generatedFrontMatters = 
    // imagine lots of sample data and workflows to create it, hence the records
    seq { for letter in ["A";"B";"C"] -> 
            { First  = letter;
              Second = letter + letter
              Third  = letter + letter + letter } }

1 个答案:

答案 0 :(得分:2)

查看FSharp.Reflection模块

// Your Code --------------------------------------------------

// I want to generate lots of sample data for the first three columns
// And I would like to avoid creating giant record types in order to
// do this task as the csv's are always changing and the records would
// have to change as well
type CumbersomeCSVRow = // 17 fields now, but imagine 212
    string * string * string * Option<int> * string * 
    Option<int> * string * string * string * string * 
    string * string * Option<float> * string * 
    Option<float> * Option<float> * string

// Here is a sample row of data
let sampleCumbersomeRow : CumbersomeCSVRow = 
    ("First","Second","Third",Some(52),"MSCI",None,"B74A123","",
     "Airlines","Transportation","","",Some(1.04293),"Updated",
     Some(0.95),Some(56.7423),"Measured")

// Record type of the sample data that I want to 'insert' into the cumbersome data type
type FirstThreeStrings = 
    { First : string; Second : string; Third : string}

// and some instances of the new data
let generatedFrontMatters = 
    // imagine lots of sample data and workflows to create it, hence the records
    seq { for letter in ["A";"B";"C"] -> 
            { First  = letter;
              Second = letter + letter
              Third  = letter + letter + letter } }

// Response ---------------------------------------------------

open FSharp.Reflection

// create a static back matter to append to
// the slicing here is the part that will need to change as the data changes
//      ++ maybe there's a better way to handle this part??
let staticBackMatter = 
    sampleCumbersomeRow
    |> FSharpValue.GetTupleFields
    |> (fun x -> x.[3 .. 16])

// cast the front matter using FSharp.Reflection
let castedFrontMatters = Seq.map FSharpValue.GetRecordFields generatedFrontMatters

// append the data arrays together, create a tuple using reflection, and downcast the result
// to your type
let generatedRows = 
    castedFrontMatters
    |> Seq.map (fun frontArray -> Array.append frontArray staticBackMatter)
    |> Seq.map (fun data -> FSharpValue.MakeTuple(data,typeof<CumbersomeCSVRow>) :?> CumbersomeCSVRow)
    |> Seq.toList

这是否是正确的F#,我不知道。