![](/img/trans.png)
[英]More elegant way to do CultureInvariant Double.parse in F#
[英]F# match with query results. Is there an elegant way to do this?
通過解析 json,我得到了 JObject 類型的結果:
let j = JObject.Parse x
我必須做的代碼是:
if j = null then
... do stuff
else if j["aa"] <> null then
... do stuff
else if j["bb"] <> null then
... do stuff
else if j["cc"] <> null and j["dd"] <> null then
... do stuff
有沒有一種干凈的方法來做這場比賽?
做類似的陳述
| _ when j.["error"] <> null ->
看起來不是很干凈。 這可以做得更好嗎?
let j = JObject.Parse x
let doSomething s = printf "%A" s
if isNull j then
()
else
[ j.["aa"]; j.["bb"]; j.["cc"] ]
|> List.tryFind (fun s -> s |> Option.ofObj |> Option.isSome)
|> doSomething
let j = JObject.Parse x
let doSomething s = printf "%A" s
if isNull j then
()
else
[ j.["aa"]; j.["bb"]; j.["cc"] ]
|> List.choose (fun s -> s |> Option.ofObj)
|> List.iter doSomething
let j = JObject.Parse x
let doSomethingA s = printf "%A" s
let doSomethingB s = printf "%A" s
let doSomethingC s = printf "%A" s
if isNull j then
()
else
[
j.["aa"], doSomethingA
j.["bb"], doSomethingB
j.["cc"], doSomethingC
]
|> List.tryFind (fun (s, _) -> s |> Option.ofObj |> Option.isSome)
|> Option.iter (fun (s, f) -> f s)
如果您創建一個返回匹配JToken
的活動模式 ...
let (|NonNull|_|) prop (o : JObject) =
o.[prop] |> Option.ofObj
你可以這樣寫:
let handleAA (a : JToken) = ()
match JObject.Parse "{}" with
| null -> () // ...
| NonNull "aa" a -> handleAA a
| NonNull "bb" b & NonNull "cc" c -> ()
| _ -> () // all other
更新
如果你需要更多的力量,Active Patterns galore...
let (|J|_|) prop (o : obj) =
match o with
| :? JObject as o -> o.[prop] |> Option.ofObj
| _ -> None
let (|Deep|_|) (path : string) (o : obj) =
let get t p = t |> Option.bind (fun t -> (``|J|_|``) p t)
match o with
| :? JToken as t ->
path.Split('.') |> Array.fold get (Option.ofObj t)
| _ -> None
...一些幫手...
let jV (t : JToken) = t.Value<string>()
let handle t = jV t |> printfn "single: %s"
let handle2 a b = printfn "(%s, %s)" (jV a) (jV b)
...解析 function...
let parse o =
match JsonConvert.DeserializeObject o with
| null -> printfn "null"
| J "aa" a -> handle a
| J "bb" b & J "cc" c -> handle2 b c
| J "bb" b & J "dd" _ -> handle b
| Deep "foo.bar" bar & Deep "hello.world" world -> handle2 bar world
| Deep "foo.bar" bar -> handle bar
| o -> printfn "val: %A" o
...然后我們 go:
parse "null" // null
parse "42" // val: 42L
parse "{ aa: 3.141 }" // single: 3.141
parse "{ bb: 2.718, cc: \"e\" }" // (2.718, e)
parse "{ bb: 2.718, dd: 0 }" // single: 2.718
parse "{ foo: { bar: \"baz\" } }" // single: baz
parse "{ foo: { bar: \"baz\" }, hello: { world: \"F#|>I❤\" } }" // (baz, F#|>I❤)
您可以創建一個活動模式來匹配非空值...
let (|NonNull|_|) = function null -> None | v -> Some v
...這將允許以下內容。
if isNull j then
//do stuff
else
match j.["aa"], j.["bb"], j.["cc"], j.["dd"] with
| NonNull aa, _, _, _ -> //do stuff
| _, NonNull bb, _, _ -> //do stuff
| _, _, NonNull cc, NonNull dd -> //do stuff
您可以為每個鍵制作一個操作列表,以便您可以為每個鍵統一應用 null 檢查邏輯。
let j = JObject.Parse x
let doStuff key value = printfn "%s=>%s" key value
如果你想為每個鍵應用 doStuff,你可以迭代。 這是您的示例,但沒有 else ,因此它對存在的每個鍵都執行此操作。
["aa", doStuff
"bb", doStuff
"cc", doStuff]
|> List.iter (fun (key,action) ->
j.TryGetValue key
|> snd
|> Option.ofObj
|> Option.iter (action key))
更緊密地匹配您的示例,其中您僅 doStuff 出現的第一個鍵可能使用選擇僅獲取有效值、操作。
["aa", doStuff
"bb", doStuff
"cc", doStuff]
|> Seq.choose (fun (key,action) ->
j.TryGetValue key
|> snd
|> Option.ofObj
|> Option.map (fun v -> action key v))
|> Seq.tryHead
如果存在匹配的鍵並且 doStuff 返回了值,則此版本還會返回應用的 doStuff 的結果。 這有點濫用 Seq 的惰性,只調用第一個值,但您也可以 map 到 function 調用 Seq.tryHead 的結果。
Option.ofObj 將變成 null -> None 和 v -> Some v
由於 JObject 是可枚舉的,因此您只需 map 就可以了
let j = JObject.Parse x |> Seq.map Option.ofObj
// j.["aa"] is an Option type now, map will only multiply the value by 3 if it exists
// otherwise it will return none.
let aa = j.["aa"] |> Option.map (fun a -> a * 3)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.