你写过:
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,有关您可以使用 Map 执行的操作,请参阅 https://msdn.microsoft.com/en-us/library/ee353880.aspx。
这是一个地图版本(这是我推荐的解决方案):
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<Key,Value>() // 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# 中工作时的首选集合。