Erlang, finding the number of occurrences of a number in a list

好久不见. 提交于 2020-01-25 04:18:11

问题


I am new to Erlang and trying to write a program that will take a list of numbers like this [1,5,4,5,3,2,2,8,11] as an input parameter of a function. The function should return a list of tuples that records the number and it's number of appearances in the list like so.

[{1,1},{2,2},{3,1},{4,1},{5,1},{8,1},{11,1}].

I have the following code

list([]) ->
  [];
list([First | Rest])  ->  
  [{First,+1} | list(Rest)].

But I dont understand how it is that I can do the counting operation? Thanks


回答1:


See 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).

In the 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

This part:

frequencies(List) ->
    frequencies(List, #{}).

let's you call the frequencies/1 function by passing it just a list. The list is then relayed to the frequencies/2 function along with an empty map to store the results.

This part:

frequencies([H|T], Freqs) ->
    Incrementer = fun(Count) -> Count+1 end,
    NewFreqs = maps:update_with(H, Incrementer, _Default=1, Freqs),
    frequencies(T, NewFreqs).

uses pattern matching to remove the first number from the List, H, then calls the function maps:update_with/4 passing the first number as the Key that should be updated in the map. The other arguments for maps:update_with/4 are the map to be updated,Freqs, and a function, Incrementer, which receives the Value associated with the Key in the map as an argument. The return value of the Incrementer function is the new Value that should be inserted for the Key in the map. If the Key does not exist in the map, then a new Key is entered into the map with the _Default Value.

maps:update_with/4 returns the updated map, NewFreqs, which is passed as an argument to the recursive function call:

frequencies(T, NewFreqs).

The first argument, T, is a List containing the remaining numbers. When all the numbers in the List have been removed, then the recursive function call will be:

frequencies([], #{ results in this map })

That function call will match this function clause:

frequencies([], Freqs) ->
    maps:to_list(Freqs);

and maps:to_list/1 converts a map to a list of {Key, Value} tuples. Because there is no recursive function call in the body of that function clause, the recursion ends, and the list of tuples is returned.

Maybe different variable names would make the code easier to follow:

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).



回答2:


Probably not the fastest (use a map instead of a tuple list if speed is a concern):

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.

With maps, the code would be simpler:

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.



回答3:


You can do it as a one-liner, but breaking it down into steps:

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).

Result:

[{1,1},{2,2},{3,1},{4,1},{5,2},{8,1},{11,1}]


来源:https://stackoverflow.com/questions/59148096/erlang-finding-the-number-of-occurrences-of-a-number-in-a-list

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!