Erlang,查找列表中数字的出现次数
Erlang, finding the number of occurrences of a number in a list
我是 Erlang 的新手,正在尝试编写一个程序,它将像这样的数字列表 [1,5,4,5,3,2,2,8,11] 作为一个输入参数功能。该函数应该 return 记录数字的元组列表及其在列表中出现的次数。
[{1,1},{2,2},{3,1},{4,1},{5,1},{8,1},{11,1}].
我有以下代码
list([]) ->
[];
list([First | Rest]) ->
[{First,+1} | list(Rest)].
但是我不明白我是如何进行计数操作的?谢谢
可能不是最快的(如果担心速度,请使用映射而不是元组列表):
count([]) ->
[];
count([H|T]) ->
count2([H|T], []).
count2([H|T], L) ->
case lists:keyfind(H, 1, L) of
{H, X} ->
L2 = lists:append(lists:delete({H, X}, L), [{H,X+1}]) ;
false ->
L2 = lists:append(L, [{H, 1}])
end,
count2(T, L2);
count2([], L) ->
L.
有了地图,代码会更简单:
count([]) ->
#{};
count(L) ->
count2(L, #{}).
count2([H|T], M) ->
Y = case maps:is_key(H, M) of
true -> #{H := X} = M,
X + 1;
false -> 1
end,
count2(T, M#{H => Y});
count2([], M) ->
M.
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).
在shell中:
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}]
Do you mind explaining how this code works step by step
这部分:
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
将第一个数字作为应在映射中更新的键传递。 maps:update_with/4
的其他参数是要更新的地图 Freqs
和一个函数 Incrementer
,它接收与地图中的键关联的值作为参数。 Incrementer
函数的 return 值是应该为映射中的键插入的新值。如果映射中不存在该键,则使用 _Default
值将新键输入到映射中。
maps:update_with/4
returns 更新的地图,NewFreqs
,它作为参数传递给递归函数调用:
frequencies(T, NewFreqs).
第一个参数 T
是一个包含剩余数字的列表。当List中的所有数字都被删除后,递归函数调用将是:
frequencies([], #{ results in this map })
该函数调用将匹配此函数子句:
frequencies([], Freqs) ->
maps:to_list(Freqs);
和 maps:to_list/1
将映射转换为 {Key, Value}
元组列表。因为在该函数子句的主体中没有递归函数调用,递归结束,并且元组列表是 returned.
也许不同的变量名会使代码更容易理解:
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).
您可以单行执行,但将其分解为多个步骤:
List = [1,5,4,5,3,2,2,8,11].
Keys = lists:usort(List).
Count = fun(V,L) -> length(lists:filter(fun(E) -> E == V end, L)) end.
> lists:map(fun(K) -> { K, Count(K,List) } end, Keys).
结果:
[{1,1},{2,2},{3,1},{4,1},{5,2},{8,1},{11,1}]
我是 Erlang 的新手,正在尝试编写一个程序,它将像这样的数字列表 [1,5,4,5,3,2,2,8,11] 作为一个输入参数功能。该函数应该 return 记录数字的元组列表及其在列表中出现的次数。
[{1,1},{2,2},{3,1},{4,1},{5,1},{8,1},{11,1}].
我有以下代码
list([]) ->
[];
list([First | Rest]) ->
[{First,+1} | list(Rest)].
但是我不明白我是如何进行计数操作的?谢谢
可能不是最快的(如果担心速度,请使用映射而不是元组列表):
count([]) ->
[];
count([H|T]) ->
count2([H|T], []).
count2([H|T], L) ->
case lists:keyfind(H, 1, L) of
{H, X} ->
L2 = lists:append(lists:delete({H, X}, L), [{H,X+1}]) ;
false ->
L2 = lists:append(L, [{H, 1}])
end,
count2(T, L2);
count2([], L) ->
L.
有了地图,代码会更简单:
count([]) ->
#{};
count(L) ->
count2(L, #{}).
count2([H|T], M) ->
Y = case maps:is_key(H, M) of
true -> #{H := X} = M,
X + 1;
false -> 1
end,
count2(T, M#{H => Y});
count2([], M) ->
M.
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).
在shell中:
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}]
Do you mind explaining how this code works step by step
这部分:
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
将第一个数字作为应在映射中更新的键传递。 maps:update_with/4
的其他参数是要更新的地图 Freqs
和一个函数 Incrementer
,它接收与地图中的键关联的值作为参数。 Incrementer
函数的 return 值是应该为映射中的键插入的新值。如果映射中不存在该键,则使用 _Default
值将新键输入到映射中。
maps:update_with/4
returns 更新的地图,NewFreqs
,它作为参数传递给递归函数调用:
frequencies(T, NewFreqs).
第一个参数 T
是一个包含剩余数字的列表。当List中的所有数字都被删除后,递归函数调用将是:
frequencies([], #{ results in this map })
该函数调用将匹配此函数子句:
frequencies([], Freqs) ->
maps:to_list(Freqs);
和 maps:to_list/1
将映射转换为 {Key, Value}
元组列表。因为在该函数子句的主体中没有递归函数调用,递归结束,并且元组列表是 returned.
也许不同的变量名会使代码更容易理解:
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).
您可以单行执行,但将其分解为多个步骤:
List = [1,5,4,5,3,2,2,8,11].
Keys = lists:usort(List).
Count = fun(V,L) -> length(lists:filter(fun(E) -> E == V end, L)) end.
> lists:map(fun(K) -> { K, Count(K,List) } end, Keys).
结果:
[{1,1},{2,2},{3,1},{4,1},{5,2},{8,1},{11,1}]