从 F# 中的地图中删除所有内容
RemoveAll from map in F#
C#:
在 C# 中我有这样的东西:
IImmutableDictionary<string, string> map = new Dictionary<string, string>
{
{"K1", "V1"},
{"K2", "V2"},
{"K3", "V3"},
}.ToImmutableDictionary();
IEnumerable<string> keys = new[] {"K1,K3"};
map = map.RemoveRange(keys);
我假设引入了方法 ImmutableDictionary<K,V>.RemoveRange Method (IEnumerable<K>)
,因为它比一系列 Remove(K)
调用更有效。它只创建一次生成的不可变对象,而不是为 keys
中要删除的每个元素创建一次。
F#:
在 F# 中实现相同目标的最佳方法是什么。我想出了这个递归解决方案:
let rec removeAll (map:Map<string, string>, keys:list<string>) =
match keys with
| [] -> map
| _ -> removeAll(map.Remove(keys |> Seq.head), keys.Tail)
但我怀疑它是否与上面的 RemoveRange
一样有效。
问题:
- F# 中
RemoveAll
最有效的等价物是什么?
- 您认为 F# 递归优化会编译成同样高效的东西吗?
Map.filter
在这里很有用,并且可能会阻止创建许多中间映射,尽管要对许多键有效地使用它,您需要先将键放入一个集合中。
let removeAll keys map =
let keySet = set keys
map |> Map.filter (fun k _ -> k |> keySet.Contains |> not)
[ 1, 2
3, 4
5, 6
7, 8 ]
|> Map
|> removeAll [1; 5]
// map [(3, 4); (7, 8)]
这太小了,可能不值得分解成一个函数。例如,如果您有一个不超过 10 个键的数组,那么首先从中创建一个集合可能效率较低。
您当前的函数是尾递归的,因此应该在不创建多个堆栈帧方面对其进行优化,但是您可以通过在列表中使用模式匹配来更简单地编写它:
let rec removeAll (map:Map<_,_>, keys:list<_>) =
match keys with
| [] -> map
| key :: rest -> removeAll(map.Remove(key), rest)
另请注意,通过删除类型注释或用 _
替换部分注释,它可以自动成为通用的,告诉编译器推断类型。
C#:
在 C# 中我有这样的东西:
IImmutableDictionary<string, string> map = new Dictionary<string, string>
{
{"K1", "V1"},
{"K2", "V2"},
{"K3", "V3"},
}.ToImmutableDictionary();
IEnumerable<string> keys = new[] {"K1,K3"};
map = map.RemoveRange(keys);
我假设引入了方法 ImmutableDictionary<K,V>.RemoveRange Method (IEnumerable<K>)
,因为它比一系列 Remove(K)
调用更有效。它只创建一次生成的不可变对象,而不是为 keys
中要删除的每个元素创建一次。
F#:
在 F# 中实现相同目标的最佳方法是什么。我想出了这个递归解决方案:
let rec removeAll (map:Map<string, string>, keys:list<string>) =
match keys with
| [] -> map
| _ -> removeAll(map.Remove(keys |> Seq.head), keys.Tail)
但我怀疑它是否与上面的 RemoveRange
一样有效。
问题:
- F# 中
RemoveAll
最有效的等价物是什么? - 您认为 F# 递归优化会编译成同样高效的东西吗?
Map.filter
在这里很有用,并且可能会阻止创建许多中间映射,尽管要对许多键有效地使用它,您需要先将键放入一个集合中。
let removeAll keys map =
let keySet = set keys
map |> Map.filter (fun k _ -> k |> keySet.Contains |> not)
[ 1, 2
3, 4
5, 6
7, 8 ]
|> Map
|> removeAll [1; 5]
// map [(3, 4); (7, 8)]
这太小了,可能不值得分解成一个函数。例如,如果您有一个不超过 10 个键的数组,那么首先从中创建一个集合可能效率较低。
您当前的函数是尾递归的,因此应该在不创建多个堆栈帧方面对其进行优化,但是您可以通过在列表中使用模式匹配来更简单地编写它:
let rec removeAll (map:Map<_,_>, keys:list<_>) =
match keys with
| [] -> map
| key :: rest -> removeAll(map.Remove(key), rest)
另请注意,通过删除类型注释或用 _
替换部分注释,它可以自动成为通用的,告诉编译器推断类型。