user3008297
user3008297

Reputation: 1

How to collect frequencies of characters using a list of tuples {char,freq} in Erlang

I am supposed to collect frequencies of characters.

freq(Sample) -> freq(Sample,[]).

freq([],Freq) ->
    Freq;
freq([Char|Rest],Freq)->
    freq(Rest,[{Char,1}|Freq]).

This function does not work in the right way. If the input is "foo", then the output will be [{f,1},{o,1},{o,1}]. But I wished to have the output like [{f,1},{o,2}]. I can't manage to modify element in a tulpe. Can anyone help me out of this and show me how it can be fixed?

Upvotes: 0

Views: 640

Answers (5)

rvirding
rvirding

Reputation: 20916

By far the easiest way is to use an orddict to store the value as it already comes with an update_counter function and returns the value in a (sorted) list.

freq(Text) ->
    lists:foldl(fun (C, D) -> orddict:update_counter(C, 1, D) end, orddict:new(), Text).

Upvotes: 3

BlackMamba
BlackMamba

Reputation: 10254

L = [list_to_atom(X) || X <- Str].
D = lists:foldl(fun({Char, _}, Acc) -> dict:update_counter(Char, 1, Acc) end, dict:new(), L).
dict:to_list(D).

Upvotes: 1

Pascal
Pascal

Reputation: 14042

a one line solution :o)

% generate a random list
L = [random:uniform(26)+$a-1 || _ <- lists:seq(1,1000)].

% collect frequency
lists:foldl(fun(X,[{[X],I}|Q]) -> [{[X],I+1}|Q] ; (X,Acc) -> [{[X],1}|Acc] end , [], lists:sort(L)).

in action

1> lists:foldl(fun(X,[{[X],I}|Q]) -> [{[X],I+1}|Q] ; (X,Acc) -> [{[X],1}|Acc] end , [], lists:sort("foo")).
[{"o",2},{"f",1}]

quite fast with short list, but the execution time increase a lot with long list (on my PC, it needs 6.5s for a 1 000 000 character text) .

in comparison, with the same 1 000 000 character text Ricardo solution needs 5 sec

I will try another version using ets.

Upvotes: 3

user235273
user235273

Reputation:

Using pattern matching and proplists.

-module(freq).
-export([char_freq/1]).

-spec char_freq(string()) -> [tuple()].
char_freq(L) -> char_freq(L, []).

char_freq([], PL) -> PL;
char_freq([H|T], PL) ->
    case proplists:get_value([H], PL) of
        undefined ->
            char_freq(T, [{[H],1}|PL]);
        N ->
            L = proplists:delete([H], PL),
            char_freq(T, [{[H],N+1}|L])
    end.

Test

1> freq:char_freq("abacabz").
[{"z",1},{"b",2},{"a",3},{"c",1}]

Upvotes: 1

Riccardo Marotti
Riccardo Marotti

Reputation: 20348

Try with something like this:

freq(Text) ->
    CharsDictionary = lists:foldl(fun(Char, Acc) -> dict:update_counter(Char, 1, Acc) end, dict:new(), Text),
    dict:fold(fun(Char, Frequency, Acc) -> [{Char, Frequency} | Acc] end, [], CharsDictionary).

The first line creates a dictionary that uses the char as key and the frequency as value (dict:update_counter).

The second line converts the dictionary in the list that you need.

Upvotes: 1

Related Questions