How to use Map.TryFind?

二次信任 提交于 2020-01-26 04:19:19

问题


When I run the code below I get an error. I am using Map.TryFind and its not working. In console, I get a red line under familyinc.TryFind(tract) and the error below.

let data =
    seq { for (state,work) in statecsv do
            let (family,income) = familyinc.TryFind(state) 
            let fam =
                match fam with 
                | Some x -> x
                | None -> "Not a Record"
            let inc = 
                match inc with 
                | Some x -> x
                | None -> "Not an income"
            yield (state,work,inc,fam)
    }

The ERROR:

error FS0001: This expression was expected to have type
    ''a * 'b'    
but here has type
    '(string * decimal) option'

回答1:


Answer to the edited question: The problem is the same as in the previous one, you are pattern matching on a tuple while you are binding an option. You should do something like this instead:

// Bind the whole option
let result = familyinc.TryFind(state)

// Pattern match on it
match result with
| Some (family , income) -> yield (state,work,family,income)
| None -> yield (state,work,"Not a Record","Not an Income")

Of course you could also do match familyinc.TryFind(tract) with, there's no need to bind to variable here.


The issue is you are pattern matching on the result of Map.TryFind() as if it would return a tuple but it actually returns an option as it may fail to find they key you are looking for.




回答2:


In all FP languages understanding option types and pattern matching is essential. In fact both of these features make FP a superior alternative to OO languages. Using option types you can avoid getting null exceptions, using pattern matching you can deconstruct values. In this case you can filter out non-existing keys, and convert the option result into normal values:

//create test dictionary
let map1 = [("a",1); ("b",2);("c",3)] |> Map.ofList

//list of keys, "d" doesn't exist in the dictionary/map
let keys = ["a";"b";"d"]

keys
|> List.map (fun x -> map1.[x])
//System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.

keys
|> List.map (fun x -> map1.TryFind(x))
//You get back a string option list, with the last element missing as the key "d" doesn't exist
//val it : int option list = [Some 1; Some 2; None]

//Method A: filter out the none existing items
keys
|> List.map (fun x -> map1.TryFind(x))
|> List.choose id  //choose will get rid of the Nones and return the actual value, not the option. id is the identity function. 

//Method B: replace the None with some default value, and also get rid of the option
//Let's say you replace each non existing value with 999
keys
|> List.map (fun x -> map1.TryFind(x))
|> List.map (Option.defaultValue 999)
//val it : int list = [1; 2; 999]

//In general if necessary you can always pattern match
let myOption1 = Some "A"
let myOption2 = None

match myOption1 with
| Some x -> x //try matching whatever is in myOption1 and returns the x portion of Some x, in this case "A"
| None -> "No value"
//val it : string = "A"

match myOption2 with 
| Some x -> x
| None -> "No value" //since the value of myOption2 is None, Some x won't match, None will match, and return "No value"
//val it : string = "No value"


来源:https://stackoverflow.com/questions/50884960/how-to-use-map-tryfind

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!