2015-06-01 126 views
0

我有以下代碼來獲取CSV文件的類型信息。如何獲取列的類型信息?我將需要將其保存到數據庫表中。從CsvProvider獲取列類型信息?

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 
.... 
+0

附註:如果你是從你的類型提供者提供的相同文件加載,你可以直接調用'的getSample()',而不是'負載(「文件名」)' –

+0

大。 'GetSample()'在這種情況下是很好的。 – ca9163d9

回答

1

我相信有人可以提供更慣用的方式來組織這一點,但至少應該工作(另請注意,我明確地沒有做任何異常處理和訪問值爲string [] option的值(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 

iterateTupleMemberTypes遞歸性是必要的,因爲一旦你的元組到達一定數量的「成員「,最後一個成員用於將所有其餘成員填充到它自己的元組中。在我的測試中,發生這種事情後,我擊中了元組的8個成員。

編輯

OP詢問有關如何修改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 

而作爲一個額外的獎勵方法,這裏是你如何能迭代通過量^ h那些造成的元組:

let rec printSchemaMembers (schema:(System.Type*string) list) = 
    match schema with 
    | (argType, name)::tail -> 
     printfn "Type: %A, Name: %s" argType name 
     printSchemaMembers tail 
    | [] -> ignore 
+0

聽起來不錯。如何更新'iterateTupleMemberTypes'函數來返回'ColumnName'的'dict' /'map'和Type? – ca9163d9

+1

我在這裏發佈了一個答案:http://stackoverflow.com/a/30590166/2894770 嵌套的元組從8列開始,因爲事實上,有System.Tuple高達8個泛型參數。 – CaringDev

+0

@RCH感謝那些信息 –