见maps:update_with/4:
frequencies(List) ->
frequencies(List, #{}).
frequencies([], Freqs) ->
maps:to_list(Freqs);
frequencies([H|T], Freqs) ->
Incrementer = fun(Count) -> Count+1 end,
NewFreqs = maps:update_with(H, Incrementer, _Default=1, Freqs),
frequencies(T, NewFreqs).
在外壳中:
1> a:frequencies([1,5,4,5,3,2,2,8,11]).
[{1,1},{2,2},{3,1},{4,1},{5,2},{8,1},{11,1}]
你介意一步一步解释这段代码是如何工作的
这部分:
frequencies(List) ->
frequencies(List, #{}).
让我们通过传递一个列表来调用frequencies/1 函数。然后将该列表与一个空映射一起转发到frequencies/2 函数以存储结果。
这部分:
frequencies([H|T], Freqs) ->
Incrementer = fun(Count) -> Count+1 end,
NewFreqs = maps:update_with(H, Incrementer, _Default=1, Freqs),
frequencies(T, NewFreqs).
使用模式匹配从列表中删除第一个数字H,然后调用函数maps:update_with/4,将第一个数字作为应该在地图中更新的Key。 maps:update_with/4 的其他参数是要更新的映射Freqs 和一个函数Incrementer,它接收与映射中的键关联的值作为参数。 Incrementer 函数的返回值是应该为映射中的键插入的新值。如果映射中不存在该键,则将具有_Default 值的新键输入映射中。
maps:update_with/4 返回更新后的映射 NewFreqs,它作为参数传递给递归函数调用:
frequencies(T, NewFreqs).
第一个参数T 是一个包含剩余数字的列表。当 List 中的所有数字都被删除后,递归函数调用将是:
frequencies([], #{ results in this map })
该函数调用将匹配该函数子句:
frequencies([], Freqs) ->
maps:to_list(Freqs);
和maps:to_list/1 将映射转换为{Key, Value} 元组的列表。因为该函数子句的主体中没有递归函数调用,所以递归结束,返回元组列表。
也许不同的变量名会使代码更容易理解:
frequencies(List) ->
frequencies(List, _ResultsMap=#{}).
frequencies([Key|Keys], ResultsMap) ->
Incrementer = fun(Value) -> Value+1 end,
NewResultsMap = maps:update_with(Key, Incrementer, _Default=1, ResultsMap),
frequencies(Keys, NewResultsMap);
frequencies([], ResultsMap) ->
maps:to_list(ResultsMap).