2014-04-03 79 views
0

我有嵌套地圖的結構:模式對現有的變量匹配

[<RequireQualifiedAccess>] 
type NestedMap = 
    | Object of Map<string,NestedMap> 
    | Value of int  

我需要修剪的結構。 代碼的目的是維護完整的映射和映射的嵌套結構,找到鍵值對,修剪沒有找到鍵值對的分支。

下面是測試NestedMap

let l2' = NestedMap.Object (List.zip ["C"; "S"; "D"] [NestedMap.Value(10); NestedMap.Value(20); NestedMap.Value(30)] |> Map.ofList) 
let l3 = NestedMap.Object (List.zip ["E"; "S"; "F"] [NestedMap.Value(100); NestedMap.Value(200); NestedMap.Value(300)] |> Map.ofList)  
let l2'' = NestedMap.Object (List.zip ["G"; "H"; "I"; "S"] [NestedMap.Value(30); l3; NestedMap.Value(40); NestedMap.Value(50)] |> Map.ofList)  
let l1 = NestedMap.Object (List.zip ["Y"; "A"; "B"] [NestedMap.Value(1); l2'; l2''] |> Map.ofList) 

這是我的代碼:

let rec pruneWithKeyValue (keyvalue: string * int) (json: NestedMap) = 
    let condition ck cv = 
     let tgtKey = (fst keyvalue) 
     let tgtVal = (snd keyvalue) 
     match (ck, cv) with 
     | (tgtKey, NestedMap.Value(tgtVal)) -> 
      printfn ">>> Found match : " 
      printfn "  ck = %s " ck 
      printfn "  tgtKey and tgtVal == %s, %i" tgtKey tgtVal 
      true 
     | _ -> false 
    match json with 
    | NestedMap.Object nmap -> 
     if (nmap |> Map.exists (fun k v -> condition k v)) then 
      json 
     else 
      printfn "Expanding w keyvalue: (%s,%i): " (fst keyvalue) (snd keyvalue) 
      let expanded = nmap |> Map.map (fun k v -> pruneWithKeyValue keyvalue v) 
      NestedMap.Object(expanded |> Map.filter (fun k v -> v <> NestedMap.Object (Map.empty))) 
    | _ -> NestedMap.Object (Map.empty) 

let pruned = pruneWithKeyValue ("S",20) l1 
let res = (pruned = l1) 

結果是不是有什麼期望:

>>> Found match : 
     ck = Y  
     tgtKey and tgtVal == Y, 1 

val pruneWithKeyValue : string * int -> json:NestedMap -> NestedMap 
val pruned : NestedMap = 
    Object 
    (map 
     [("A", Object (map [("C", Value 10); ("D", Value 30); ("S", Value 20)])); 
     ("B", 
     Object 
      (map 
       [("G", Value 30); 
       ("H", 
       Object 
        (map [("E", Value 100); ("F", Value 300); ("S", Value 200)])); 
       ("I", Value 40); ("S", Value 50)])); ("Y", Value 1)]) 
val remainsTheSame : bool = true 

的代碼表示,輸出數據結構保持不變(val remainsTheSame : bool = true)。更有趣的是,不知何故keyvalue元組包含鍵值對的功能是搜索得到了改進:

>>> Found match : 
     ck = Y  
     tgtKey and tgtVal == Y, 1 

這就是問題所在。事實上,如果我硬編碼keyvalue元組:

let rec pruneWithKeyValue (keyvalue: string * int) (json: NestedMap) = 
    let condition ck cv = 
     let tgtKey = (fst keyvalue) 
     let tgtVal = (snd keyvalue) 
     match (ck, cv) with 
     | ("S", NestedMap.Value(20)) -> 
      printfn ">>> Found match : " 
      printfn "  ck = %s " ck 
      printfn "  tgtKey and tgtVal == %s, %i" tgtKey tgtVal 
      true 
     | _ -> false 
    match json with 
    | NestedMap.Object nmap -> 
     if (nmap |> Map.exists (fun k v -> condition k v)) then 
      json 
     else 
      printfn "Expanding w keyvalue: (%s,%i): " (fst keyvalue) (snd keyvalue) 
      let expanded = nmap |> Map.map (fun k v -> pruneWithKeyValue keyvalue v) 
      NestedMap.Object(expanded |> Map.filter (fun k v -> v <> NestedMap.Object (Map.empty))) 
    | _ -> NestedMap.Object (Map.empty) 

let pruned = pruneWithKeyValue ("S",20) l1 
let remainsTheSame = (pruned = l1) 

結果(耶)想要的結果:

Expanding w keyvalue: (S,20): 
>>> Found match : 
     ck = S  
     tgtKey and tgtVal == S, 20 
Expanding w keyvalue: (S,20): 
Expanding w keyvalue: (S,20): 

val pruneWithKeyValue : string * int -> json:NestedMap -> NestedMap 
val pruned : NestedMap = 
    Object 
    (map 
     [("A", Object (map [("C", Value 10); ("D", Value 30); ("S", Value 20)]))]) 
val remainsTheSame : bool = false 

這可能是微不足道的,但我不明白的地方,以及如何keyvalue最終被修改後,阻止我通過參數化鍵值元組獲得正確的輸出。

回答

3

您無法對現有變量進行模式匹配,在您的原始代碼中tgtKeytgtVal將是新的綁定,與現有的綁定無關,這些綁定將會被遮蔽。

因此改變你的比賽:

match (ck, cv) with 
    | (tgtKey, NestedMap.Value(tgtVal)) -> 

到:

match (ck, cv) with 
    | (k, NestedMap.Value v) when (k, v) = (tgtKey, tgtVal) -> 

或者只是:

match (ck, cv) with 
    | x when x = (tgtKey, NestedMap.Value(tgtVal)) -> 
+0

是的,謝謝。我忘了使用* Guard在模式*上:「請注意,由於文本以外的值不能在模式中使用,所以如果必須將某些輸入與某個值進行比較,則必須使用when子句。」 [鏈接](http://msdn.microsoft.com/en-us/library/dd233242.aspx) – NoIdeaHowToFixThis