给定的是一个文本文件,其中键和值按交替顺序排列,如下所示:
KeyA
ValueA
KeyB
ValueB
KeyC
ValueC
...
我想从该数据创建一个字典/哈希表。我将如何以实用的方式实现这一目标?
答案 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.choose或Seq.choose将其拆分为奇数/偶数列表,然后在这两个列表上使用List.zip来获取将它们放入键/值元组列表中。