Reputation: 570
Given a string such as
one:1.0|two:2.0|three:3.0
how do we create a dictionary of the form string: float?
open System
open System.Collections.Generic
let ofSeq (src:seq<'a * 'b>) =
// from fssnip
let d = new Dictionary<'a, 'b>()
for (k,v) in src do
d.Add(k,v)
d
let msg = "one:1.0|two:2.0|three:3.0"
let msgseq = msg.Split[|'|'|] |> Array.toSeq |> Seq.map (fun i -> i.Split(':'))
let d = ofSeq msgseq // The type ''a * 'b' does not match the type 'string []'
This operation would be inside a tight loop so efficiency would be a plus. Although I'd like to see a simple solution as well just to get my F# bearings.
Thanks.
Upvotes: 3
Views: 1436
Reputation: 12184
How about something like this:
let msg = "one:1.0|two:2.0|three:3.0"
let splitKeyVal (str : string) =
match str.Split(':') with
|[|key; value|] -> (key, System.Double.Parse(value))
|_ -> invalidArg "str" "str must have the format key:value"
let createDictionary (str : string) =
str.Split('|')
|> Array.map (splitKeyVal)
|> dict
|> System.Collections.Generic.Dictionary
You could drop the System.Collections.Generic.Dictionary
if you don't mind an IDictionary
return type.
If you expect the splitKeyVal
function to fail then you'd be better off expressing it as a function that returns option, e.g.:
let splitKeyVal (str : string) =
match str.Split(':') with
|[|key; valueStr|] ->
match System.Double.TryParse(valueStr) with
|true, value -> Some (key, value)
|false, _ -> None
|_ -> None
But then you'd also have to decide how you wanted to handle failure in the createDictionary
function.
Upvotes: 6
Reputation: 5049
Not sure about the perf side but if you're sure of your input and can "afford" a warning you can go with :
let d =
msg.Split '|'
|> Array.map (fun s -> let [|key; value|] (*warning here*) = s.Split ':' in key, value)
|> dict
|> System.Collections.Generic.Dictionary // optional if a IDictionary<string, string> suffice
Upvotes: 2