从CsvProvider获取列类型信息?

时间:2015-06-01 18:52:30

标签: f# f#-data

我有以下代码来获取CSV文件的类型信息。如何获取列的类型信息?我需要将它保存到数据库表中。

open FSharp.Data

type MyFile = CsvProvider<"""C:\temp\sample.csv""">

[<EntryPoint>]
let main argv = 
    let myFile = MyFile.Load("""C:\temp\sample.csv""")

    printfn "%A" ((myFile.Rows |> Seq.head).GetType())
    // Write the type information of myFile columns to a table

    for row in myFile.Rows do
        printfn "%A" row
    0 

函数((myFile.Rows |> Seq.head).GetType())返回基本F#类型的嵌入元组,并且缺少标题名称。

System.Tuple`8[System.Int32,System.Int32,System.String,System.Int32,System.Int32
,System.String,System.String,System.Tuple`8[System.Int32,System.String,System.De
cimal,System.Decimal,System.Decimal,System.Decimal,System.Int32,System.Tuple`8[S
ystem.Decimal,System.Decimal,System.Decimal,System.Nullable`1[System.Int32],Syst
em.String,System.Boolean,System.Int32,System.Tuple`8[System.Decimal,System.Int32
,System.Int32,System.Decimal,System.Int32,System.Nullable`1[System.Int32],System
.Int32,System.Tuple`8[System.Decimal,System.Nullable`1[System.Int32],System.Null
able`1[System.Int32],System.Nullable`1[System.Int32],System.Decimal,System.Decim
al,System.String,System.Tuple`8[System.String,System.String,System.String,System
.String,System.String,System.String,System.String,System.Tuple`8[System.String,S
ystem.String,System.String,System.String,System.String,System.String,System.Null
able`1[System.Int32],System.Tuple`8[System.String,System.String,System.Nullable`
1[System.Int32],System.String,System.String,System.String,System.String,System.T
uple`8[System.String,System.String,System.String,System.String,System.String,Sys
tem.String,System.String,System.Tuple`1[System.String]]]]]]]]]]

预期产出,

ColumnA int
ColumnB datetime
ColumnC varchar
....

1 个答案:

答案 0 :(得分:1)

我相信有人可以提供一种更惯用的方式来组织这个,但这至少应该有用(注意我也明确没有做任何异常处理和访问string [] option值的值{{1 }}))。参数在新行上用于格式化,仅供参考:

Headers

并称之为:

let rec iterateTupleMemberTypes (tupleArgTypes: System.Type[]) 
    (columnNames: string[]) 
    (startingIndex : int) =
    let mutable index = startingIndex
    for t in tupleArgTypes do
        match t.IsGenericType with
        | true -> iterateTupleMemberTypes (t.GetGenericArguments()) columnNames index
        | false ->
            printfn "Name: %s Type: %A" (columnNames.[index]) t
            index <- index + 1

let firstRow = MyFile.Rows |> Seq.head let tupleType = firstRow.GetType() let tupleArgTypes = tupleType.GetGenericArguments() iterateTupleMemberTypes tupleArgTypes MyFile.Headers.Value 0 的递归性质是必要的,因为一旦你的元组到达一定数量的“成员”,最后一个成员就会用来将所有剩余的成员填充到它自己的元组中。在我的测试中,一旦我击中了元组的8个成员,就会发生这种情况。

修改

OP在评论中询问如何修改iterateTupleMemberTypes以建立类型/名称对的集合,这就是(我决定将它们作为元组放置):

iterateTupleMemberTypes

这样称呼:

let iterateTupleMemberTypes (tupleArgTypes: System.Type[]) (columnNames: string[]) =
    let rec iterateRec (argTypes: System.Type list) (values) (index) =
        match argTypes with
        | [] -> List.rev values
        | head :: tail when head.IsGenericType -> 
            iterateRec (List.ofArray (head.GetGenericArguments())) values index
        | head :: tail -> 
            iterateRec tail ((head, columnNames.[index])::values) (index + 1)
    iterateRec (List.ofArray tupleArgTypes) List.empty 0

作为额外的奖励方法,这里是你如何迭代这些产生的元组:

let tupleType = firstRow.GetType()
let tupleArgTypes = tupleType.GetGenericArguments()
let schemaStuff = iterateTupleMemberTypes tupleArgTypes MyFile.Headers.Value