2010-06-05 197 views
9

我有一個datareader,我想返回它的行集合後,閱讀書像一天,我無法找到最好的方式來做它在f#中。我能做到這一點普通的C#的方式在F#,但其實不是這樣的,我使用F#F#使用while循環

這裏是我想實現

let values = 
    while reader.Read() do 
     yield reader.GetString(0), reader.GetInt64(1) 

以上就是我是多麼努力做

  • 所有值得到收集到的值,這可能是詞典]或元組或任何託收
  • 產量不能while循環中使用的,但是這就是我試圖做

什麼能實現這個

回答

13

F#還提供數組和序列的列表理解。

let records_as_list = 
    [ 
     while reader.Read() 
      do yield (reader.GetString(0), reader.GetInt64(1)) 
    ] 

let records_as_array = 
    [| 
     while reader.Read() 
      do yield (reader.GetString(0), reader.GetInt64(1)) 
    |] 

let records_as_sequence = 
    seq { 
     while reader.Read() 
      do yield (reader.GetString(0), reader.GetInt64(1)) 
    } 

F#內置了一個方便的詞典功能稱爲dict

let records_as_IDictionary = dict records_as_sequence 
7

您可以使用序列表達式來實現枚舉的最佳方式:

let records = seq { while reader.NextResult() do yield (reader.GetString(0), reader.GetInt64(1)) } 

如果需要兩個以上的字段,可以產生列索引地圖(或名稱) - >字段值(未經測試的代碼):

let dbSchema = reader.GetSchemaTable() 

let makeMap (rdr : IDataReader) (schema : DataTable) = 
    schema.Columns |> Seq.cast<DataColumn> |> Seq.map (fun col -> (col.ColumnName, rdr.[col.ColumnName])) |> Map.ofSeq 

let records = seq { while reader.NextResult() do yield (makeMap reader dbSchema) } 
+0

問題的序列是,它延遲加載,所以當你想在這種情況下,閱讀器來閱讀它會通過附加關閉 – mamu 2010-06-05 20:57:01

+0

容易固定|> Seq.toList到最後一排實現收集。 – Mau 2010-06-06 13:32:32

3

對於這種類型的任務,我想先將輸入轉換爲一串字符串。

.NET 4.0提供readlines方法,它的返回值的類型是seq<string>

open System.IO 
    let readLinesSeq = File.ReadLines 

在較低版本.NET中,一個需要實現這樣的功能:

let readLines filePath = seq { 
    use sr = new StreamReader (filePath) 
    while not sr.EndOfStream do 
    yield sr.ReadLine() 
    } 
+0

問題是關於'System.Data.IDataReader' - 不是文件輸入... – 2010-06-05 16:55:39

+0

@ Joel..Oops ...這個想法應該是相似的...... – 2010-06-05 17:03:46

+0

是的,基本的想法是一樣的。 – 2010-06-05 17:16:51

0

嗯,我們是不是在這裏討論文件,但是,在早期的.NET版本中,您可以使用(使用小文件):

reader.ReadToEnd().Split(System.Environment.NewLine.ToCharArray()) 

其中reader是一個TextReader。

+0

如果文件很大,應該避免讀取所有內容並拆分。 – 2010-06-05 15:42:39

+0

在這個問題中,'reader'實際上是一個IDataReader,而不是TextReader – 2010-06-05 17:16:18

2

我可以通過添加擴展屬性更一般地處理這個問題IDataReader它能將任意的DataReader成seq<IDataRecord> ...

[<AutoOpen>] 
module DataReaderEx = 
    open System.Data 

    type IDataReader with 
     member this.toSeq = 
      seq { while this.Read() do yield this :> IDataRecord } 

這將允許您使用的普通功能3210模塊上任何的DataReader:

reader.toSeq 
|> Seq.map (fun row -> row.GetString(0), row.GetInt64(1))