如何使用Map.TryFind?

时间:2018-06-16 04:28:26

标签: f#

当我运行下面的代码时,我收到一个错误。我正在使用Map.TryFind并且它无法正常工作。在控制台中,我在familyinc.TryFind(tract)下面出现一条红线,下面是错误。

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)
    }

错误:

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

2 个答案:

答案 0 :(得分:3)

回答编辑过的问题:问题与前一个问题相同,在绑定选项时,您在元组上进行模式匹配。你应该做这样的事情:

// 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")

当然你也可以做match familyinc.TryFind(tract) with,这里不需要绑定变量。

问题是你对Map.TryFind()的结果进行模式匹配,好像它会返回一个元组,但它实际上会返回一个option,因为它可能无法找到你正在寻找的键。 / p>

答案 1 :(得分:1)

在所有FP语言中,了解选项类型和模式匹配至关重要。事实上,这两个特性使FP成为OO语言的优秀替代品。使用选项类型可以避免获得null异常,使用模式匹配可以解构值。在这种情况下,您可以过滤掉不存在的密钥,并将option结果转换为正常值:

//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"
相关问题