"F#"中的字典 "Subsetting"
"F#"中的字典 "Subsetting"
我是一个F#的初学者,我正在尝试编写一个函数来给定一个列表来截取字典并返回结果。
我尝试了这个方法,但它不起作用。
let Subset (dict:Dictionary<'T,'U>) (sub_list:list<'T>) = let z = dict.Clear sub_list |> List.filter (fun k -> dict.ContainsKey k) |> List.map (fun k -> (k, dict.TryGetValue k) ) |> List.iter (fun s -> z.Add s) |> List.iter (fun s -> z.Add s);; --------------------------------------^^^ stdin(597,39): error FS0039: The field, constructor or member 'Add' is not defined
也许F#中有本地函数可以这样做?
谢谢
编辑
感谢@TheInnerLight他下方的答案
你能不能多教教我,告诉我如果我想返回被修改的原始变量应该如何调整那个函数?
(当然可以从调用该函数的地方开始,用临时变量调用它,然后重新分配)
您写道:
let z = dict.Clear
z
的类型为 unit->unit
,但您正在调用 z.Add
。
我怀疑您想写
let subset (dict:Dictionary<'T,'U>) (sub_list:list<'T>) = let z = Dictionary<'T,'U>() // create new empty dictionary sub_list |> List.filter (fun k -> dict.ContainsKey k) |> List.map (fun k -> (k, dict.[k]) ) |> List.iter (fun s -> z.Add s) z
TryGetValue
在 F# 中将返回 bool*'U
类型的值,但如果您已经使用 ContainsKey
进行了过滤,那么您可能想直接使用 dict.[k]
进行查找。
请注意,Dictionary
是可变集合,因此如果您实际调用 dict.Clear()
,它不会返回一个新的空字典,而是会改变现有的字典,清除所有元素。用于键值关系的不可变 F# 数据结构通常是 Map
,具体内容请参见https://msdn.microsoft.com/en-us/library/ee353880.aspx 中关于 Map
的内容。
这是一个 Map
版本(这是我推荐的解决方案):
let subset map subList = subList |> List.choose (fun k -> Option.map (fun v -> k,v) (Map.tryFind k map)) |> Map.ofList
编辑(响应于问题编辑修改输入变量的部分):
可以使用可变变量上的破坏性更新操作符 <-
更新现有的字典。
选项1:
let mutable dict = Dictionary() // replace this with initial dictionary let lst = [] // list to check against dict <- sublist dict lst
同样,我的第一个函数可以更改为仅执行副作用(移除不需要的元素)。
选项2:
let subset (d : System.Collections.Generic.Dictionary<'T,'U>) (sub_list : list<'T>) = sub_list |> List.filter (d.ContainsKey >> not) |> List.iter (d.Remove >> ignore)
对于初学 F# 的人,我不太推荐选项1,而且我真的不推荐选项2。
功能性方法是偏好不可变值、纯函数等。这意味着您最好将函数视为定义数据转换而不是定义要执行的指令列表。
因为 F# 是一种多范式语言,所以在早期阶段很容易回到命令式模式,但即使这些习语感觉奇怪和不舒服,强制自己采用该语言的标准范式和惯用方法可能会使您从学习新语言中受益。
像 Map
和 list
这样的不可变数据结构在共享数据和提供良好的时间复杂性方面非常高效,因此在使用 F# 时,这些数据结构通常是您的首选集合。