F # работает с циклом while - PullRequest
9 голосов
/ 05 июня 2010

У меня есть устройство чтения данных, и я хочу вернуть из него коллекцию строк, после чтения книг в течение дня я не могу найти лучший способ сделать это в f #. Я могу сделать это обычным C # способом в F #, но это не то, почему я использую f #

Вот что я пытаюсь достичь

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

выше, как я пытаюсь сделать

  • все значения собраны в значения, которые могут быть как двукратными, так и кортежами или любой коллекцией
  • yield не может использоваться в цикле while, но это то, что я пытаюсь сделать

Что может быть лучшим способом достижения этого

Ответы [ 5 ]

14 голосов
/ 05 июня 2010

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 голосов
/ 05 июня 2010

Вы можете использовать выражения последовательности для реализации перечислителей:

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) }
3 голосов
/ 05 июня 2010

Для такого рода задач я хотел бы сначала перенести ввод в последовательность строк.

.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 ()
   }
2 голосов
/ 05 июня 2010

Я мог бы подойти к этой проблеме более обобщенно, добавив в IDataReader свойство расширения, которое превращает любой носитель данных в seq<IDataRecord> ...

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

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

Это позволит вам использовать обычные функции из модуля Seq на любом устройстве чтения данных:

reader.toSeq
|> Seq.map (fun row -> row.GetString(0), row.GetInt64(1))
0 голосов
/ 05 июня 2010

Ну, мы не говорим о файлах здесь, однако, в более ранних версиях .NET вы можете сделать (с небольшими файлами):

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

Где reader - TextReader.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...