如果 Map 包含键 return 值,否则 return 0
If Map contains key return value, otherwise return 0
我是 F# 的新手,想按照标题所说的去做,但我不断收到这些类型错误。
我知道这行得通:
> let rec validString2 =
function
| a -> Map.find a
> validString2 "x" (Map.ofList [("x", 5)]);;
>val it: int = 5
但我想要 return Map.find a
只有 如果 a
在地图上,否则我想要 return 0。当我尝试这个时:
let rec validString =
function
| a -> if (Map.containsKey a) then Map.find a else 0
我收到的错误消息(以及 Map.containsKey a
下的红色下划线):
This expression was expected to have type
'bool'
but here has type
'Map<'a,'b> -> bool'
如果我尝试也会发生同样的情况:
let validString =
function
| Some x -> x
| None -> 0
let rec evalValidString =
function
| V a -> validString (Map.tryFind a)
我似乎误解了地图类型的工作原理。我不明白 bool 与 Map<'a, 'b> -> bool 有何不同。地图函数 return 是一个布尔值,我应该可以对其求值。
我认为这里的问题是您必须指定要搜索的地图。在下面的函数中,我将其命名为 myMap
:
let myLookup (key : string) myMap =
myMap
|> Map.tryFind key // does the key exist in myMap?
|> Option.defaultValue 0 // if not, return 0
请注意 myMap
是 Map<string, int>
类型的值。然后您可以按如下方式使用此函数:
let aMap = Map.ofList [("x", 5)]
let xValue = myLookup "x" aMap
let yValue = myLookup "y" aMap
printfn "%A" (xValue, yValue) // 5, 0
我知道这个问题已经有一个公认的答案,但我认为一些进一步的评论也可能会增加您对 F# 的学习:
let rec validString2 =
function
| a -> Map.find a
validString2 "x" (Map.ofList [("x", 5)]);;
val it: int = 5
rec
表示这是一个递归函数,但函数体中没有 调用validString
。它不是递归函数,因此不需要 rec
:
let validString2' = function | a -> Map.find a
- 现在使用函数是一种模式匹配,它使
validString2
的最后一个参数隐含。可以用 match
明确说明吗?
let validString2'' a = match a with a -> Map.find a
- 是的!因为,无论它是什么,都在
a
中匹配,因此只需要 one 分支。即根本不需要模式匹配:
let validString2''' a = Map.find a
但是 Map.find
需要 两个 个参数,但这里只有一个 (a
)。所以 validString2
是一个 部分应用的 函数,仍在等待第二个参数,即要在 a
中找到的实际映射。这解释了 validString
中的错误因为 Map.contains
和 Map.find
都需要第二个参数,并且作为部分应用函数,它们具有类型签名 'Map<'a,'b> -> bool'
(Map.contains k
) 和 'Map<'a,'b> -> 'b
(Map.find k
它还不知道 'b 分别是 int
)。因此你的错误信息。
最后,您可以将您的原始解决方案演变成:
let validString' k m = if Map.contains k m then Map.find k m else 0
因此在这种情况下不需要模式匹配或部分应用函数,但希望这有助于您在未来的使用中理解这些。
更新:
- 解决方案 (4) 需要对数据进行两次传递,第一次是
Map.contains
- O(log(N))
- 第二次是 Map.find
- 也是 O(log(N))
。我们可以单程通过吗?
let validString'' k m = if Map.contains k m then m[k] else 0
- 但是这两个操作仍然是
O(log(N))
,因为m[k]
是而不是 O(1)
,所以这是仍然 2*O(log(N))
。我们能做得更好吗?这是您查看 try...
集合函数变体的地方。在这种情况下,您需要 map.tryFind
其中 returns 一个选项,带有 Some value
或 None
- 如果密钥不存在。这是一个单程O(log(N))
解决方案:
let validString''' k m =
match Map.tryFind k m with
| Some v -> v
| None -> 0
- 这个模式匹配表达式有自己的收集功能
Option.defaultValue
,这就引出了前面给出的解决方案和标记的正确答案。
我是 F# 的新手,想按照标题所说的去做,但我不断收到这些类型错误。
我知道这行得通:
> let rec validString2 =
function
| a -> Map.find a
> validString2 "x" (Map.ofList [("x", 5)]);;
>val it: int = 5
但我想要 return Map.find a
只有 如果 a
在地图上,否则我想要 return 0。当我尝试这个时:
let rec validString =
function
| a -> if (Map.containsKey a) then Map.find a else 0
我收到的错误消息(以及 Map.containsKey a
下的红色下划线):
This expression was expected to have type
'bool'
but here has type
'Map<'a,'b> -> bool'
如果我尝试也会发生同样的情况:
let validString =
function
| Some x -> x
| None -> 0
let rec evalValidString =
function
| V a -> validString (Map.tryFind a)
我似乎误解了地图类型的工作原理。我不明白 bool 与 Map<'a, 'b> -> bool 有何不同。地图函数 return 是一个布尔值,我应该可以对其求值。
我认为这里的问题是您必须指定要搜索的地图。在下面的函数中,我将其命名为 myMap
:
let myLookup (key : string) myMap =
myMap
|> Map.tryFind key // does the key exist in myMap?
|> Option.defaultValue 0 // if not, return 0
请注意 myMap
是 Map<string, int>
类型的值。然后您可以按如下方式使用此函数:
let aMap = Map.ofList [("x", 5)]
let xValue = myLookup "x" aMap
let yValue = myLookup "y" aMap
printfn "%A" (xValue, yValue) // 5, 0
我知道这个问题已经有一个公认的答案,但我认为一些进一步的评论也可能会增加您对 F# 的学习:
let rec validString2 =
function
| a -> Map.find a
validString2 "x" (Map.ofList [("x", 5)]);;
val it: int = 5
rec
表示这是一个递归函数,但函数体中没有 调用validString
。它不是递归函数,因此不需要rec
:
let validString2' = function | a -> Map.find a
- 现在使用函数是一种模式匹配,它使
validString2
的最后一个参数隐含。可以用match
明确说明吗?
let validString2'' a = match a with a -> Map.find a
- 是的!因为,无论它是什么,都在
a
中匹配,因此只需要 one 分支。即根本不需要模式匹配:
let validString2''' a = Map.find a
但是
Map.find
需要 两个 个参数,但这里只有一个 (a
)。所以validString2
是一个 部分应用的 函数,仍在等待第二个参数,即要在a
中找到的实际映射。这解释了validString
中的错误因为Map.contains
和Map.find
都需要第二个参数,并且作为部分应用函数,它们具有类型签名'Map<'a,'b> -> bool'
(Map.contains k
) 和'Map<'a,'b> -> 'b
(Map.find k
它还不知道 'b 分别是int
)。因此你的错误信息。最后,您可以将您的原始解决方案演变成:
let validString' k m = if Map.contains k m then Map.find k m else 0
因此在这种情况下不需要模式匹配或部分应用函数,但希望这有助于您在未来的使用中理解这些。
更新:
- 解决方案 (4) 需要对数据进行两次传递,第一次是
Map.contains
-O(log(N))
- 第二次是Map.find
- 也是O(log(N))
。我们可以单程通过吗?
let validString'' k m = if Map.contains k m then m[k] else 0
- 但是这两个操作仍然是
O(log(N))
,因为m[k]
是而不是O(1)
,所以这是仍然2*O(log(N))
。我们能做得更好吗?这是您查看try...
集合函数变体的地方。在这种情况下,您需要map.tryFind
其中 returns 一个选项,带有Some value
或None
- 如果密钥不存在。这是一个单程O(log(N))
解决方案:
let validString''' k m =
match Map.tryFind k m with
| Some v -> v
| None -> 0
- 这个模式匹配表达式有自己的收集功能
Option.defaultValue
,这就引出了前面给出的解决方案和标记的正确答案。