分组交替数据

时间:2011-02-26 23:19:20

标签: f# functional-programming hashtable grouping

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

KeyA
ValueA
KeyB
ValueB
KeyC
ValueC
...

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

5 个答案:

答案 0 :(得分:6)

@BrokenGlass正确认为Seq.pairwise是最适合提取数据的球。但是对于更实用的解决方案,请使用不可变Microsoft.FSharp.Collections.Map而不是可变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

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

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

答案 1 :(得分:5)

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

我编写了一个计算构建器,允许您使用IEnumerator(参见full source code on 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

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

答案 2 :(得分:3)

我会做这样的事情,虽然我不确定这是否是最“功能性”的方法:

let dic = Dictionary<string,string>()
File.ReadAllLines(@"keyvalue.txt")
|> Seq.pairwise
|> Seq.iteri( fun i (a,b)-> if i % 2 = 0 then dic.Add(a,b))

答案 3 :(得分:2)

let loadFile path =
    let rec loop acc = function
    | k::v::rest -> loop ((k, v)::acc) rest
    | []         -> dict acc
    | _          -> failwith "odd number of lines"

    path |> System.IO.File.ReadAllLines |> List.ofArray |> loop []

答案 4 :(得分:0)

将其分解为字符串列表,使用List.chooseSeq.choose将其拆分为奇数/偶数列表,然后在这两个列表上使用List.zip来获取将它们放入键/值元组列表中。