分组交替数据

fjd*_*ont 3 f# grouping functional-programming hashtable

给定是一个文本文件,其中键和值按交替顺序排列,如下所示:

KeyA
ValueA
KeyB
ValueB
KeyC
ValueC
...
Run Code Online (Sandbox Code Playgroud)

我想从该数据创建一个字典/哈希表.我将如何以功能性方式实现这一目标?

Ste*_*sen 6

@BrokenGlass是正确的球,认为Seq.pairwise它是提取数据的最佳选择.但是对于更实用的解决方案,请使用immutable Microsoft.FSharp.Collections.Map而不是mutable System.Collections.Generic.Dictionary:

System.IO.File.ReadAllLines @"keyvalue.txt"
|> Seq.pairwise
|> Seq.mapi (fun i x -> if i % 2 = 0 then Some(x) else None)
|> Seq.choose id
|> Map.ofSeq
Run Code Online (Sandbox Code Playgroud)

如果您的数据文件很大,请考虑将值作为流读取,以获得更好的性能:

seq { 
    use sr = System.IO.File.OpenText @"keyvalue.txt"
    while(not sr.EndOfStream) do yield (sr.ReadLine(), sr.ReadLine())
}
|> Map.ofSeq
Run Code Online (Sandbox Code Playgroud)


Tom*_*cek 5

我认为之前发布的所有答案都给出了很好的解决方案.有趣的是,这不是使用F#序列表达式可以优雅地解决的问题 - 您必须使用列表和递归,一些棘手的函数(例如pairwise)或使用IEnumerator接口.

我写了一个允许你使用的计算构建器IEnumerator(参见fssnip.net上完整源代码).使用这个计算,你可以非常好地解决它:

let loadFile path = 
  // Recursive function that generates IEnumerator of key * value pairs
  let rec loop source = iter {
    // Read key & value and continue if both are available
    let! key = source
    let! value = source
    match key, value with
    | Some key, Some value -> 
       // Produce key * value pair and continue looping
       yield key, value
       yield! loop source
    | _ -> () }

  // Create sequence that reads data and convert it to dictionary
  Enumerator.toSeq (fun () ->
    loop (File.ReadAllLines(@"keyvalue.txt").GetEnumerator())) |> dict
Run Code Online (Sandbox Code Playgroud)

我发现iter计算非常好 - 在某些情况下你无法用F#解决问题seq.然后你可以使用递归和列表 - 但是同样的递归模式也可以使用非常整齐地编写iter.