List Erlang,查找列表中某个数字的出现次数

List Erlang,查找列表中某个数字的出现次数,list,erlang,tail-recursion,List,Erlang,Tail Recursion,我是Erlang新手,正在尝试编写一个程序,将[1,5,4,5,3,2,2,8,11]这样的数字列表作为函数的输入参数。函数应该返回一个元组列表,该列表记录了元组的数量及其在列表中的出现次数,如下所示 [{1,1}、{2,2}、{3,1}、{4,1}、{5,1}、{8,1}、{11,1}] 我有以下代码 list([]) -> []; list([First | Rest]) -> [{First,+1} | list(Rest)]. 但是我不明白我怎么能做计数操作?

我是Erlang新手,正在尝试编写一个程序,将[1,5,4,5,3,2,2,8,11]这样的数字列表作为函数的输入参数。函数应该返回一个元组列表,该列表记录了元组的数量及其在列表中的出现次数,如下所示

[{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.

如果速度是一个问题,可能不是最快的使用映射而不是元组列表:

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.
见:

在外壳中:

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([H|T], Freqs) ->
    Incrementer = fun(Count) -> Count+1 end,
    NewFreqs = maps:update_with(H, Incrementer, _Default=1, Freqs),
    frequencies(T, NewFreqs).
让我们通过只传递一个列表来调用frequencies/1函数。然后,该列表与一个空映射一起中继到frequencies/2功能以存储结果

本部分:

frequencies(List) ->
    frequencies(List, #{}).
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_,使用/4传递第一个数字作为应该在映射中更新的键。map:update_with/4的其他参数是要更新的map,Freqs和一个函数Incrementer,它接收与map中的键关联的值作为参数。Incrementer函数的返回值是应该为映射中的键插入的新值。如果该键在地图中不存在,则会在地图中输入一个带有_默认值的新键

maps:update_with/4返回更新后的映射NewFreqs,该映射作为参数传递给递归函数调用:

frequencies(T, NewFreqs).
第一个参数T是一个包含剩余数字的列表。删除列表中的所有数字后,递归函数调用将为:

frequencies([], #{ results in this map })
该函数调用将匹配此函数子句:

frequencies([], Freqs) ->
    maps:to_list(Freqs);
and 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).
见:

在外壳中:

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([H|T], Freqs) ->
    Incrementer = fun(Count) -> Count+1 end,
    NewFreqs = maps:update_with(H, Incrementer, _Default=1, Freqs),
    frequencies(T, NewFreqs).
让我们通过只传递一个列表来调用frequencies/1函数。然后,该列表与一个空映射一起中继到frequencies/2功能以存储结果

本部分:

frequencies(List) ->
    frequencies(List, #{}).
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_,使用/4传递第一个数字作为应该在映射中更新的键。map:update_with/4的其他参数是要更新的map,Freqs和一个函数Incrementer,它接收与map中的键关联的值作为参数。Incrementer函数的返回值是应该为映射中的键插入的新值。如果该键在地图中不存在,则会在地图中输入一个带有_默认值的新键

maps:update_with/4返回更新后的映射NewFreqs,该映射作为参数传递给递归函数调用:

frequencies(T, NewFreqs).
第一个参数T是一个包含剩余数字的列表。删除列表中的所有数字后,递归函数调用将为:

frequencies([], #{ results in this map })
该函数调用将匹配此函数子句:

frequencies([], Freqs) ->
    maps:to_list(Freqs);
and 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).

您可以将其作为一个衬里,但可以将其分解为以下步骤:

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}]

您可以将其作为一个衬里,但可以将其分解为以下步骤:

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}]

谢谢你。你介意一步一步地解释这段代码是如何工作的吗?谢谢。你介意一步一步地解释一下这个代码是如何工作的吗。