Warning: use of operator '<' has no effect? - erlang

I am new to erlang and am trying to implement a simple function as follows:
% * ChatServers is a dictionary of usernames with tuples of the form:
% {server, Pid, Reference,LoggedInUsers}
get_chat_server([], _) ->
undefined;
get_chat_server([Key|_], ChatServers) ->
{server, Pid, Reference,LoggedInUsers} = dict:fetch(Key,ChatServers),
LoggedInUsers < 100,
{server, Pid, Reference,LoggedInUsers};
get_chat_server([_|T], ChatServers) ->
get_chat_server(T, ChatServers).
Basically what I am trying to do is find the first tuple of my dictionary whose LoggedInUsers number is less than 100.
However, once I compile my code, I get the following 2 warnings:
main_server_distributed.erl:63: Warning: use of operator '<' has no
effect main_server_distributed.erl:66: Warning: this clause cannot
match because a previous clause at line 61 always matches
I have some experience with prolog and as far as I recall this is a valid use of pattern matching and recursion. Could you please point out what am I doing wrong here? Thanks in advance.

The body of a clause (everything to the right of the ->) is not a list of conditions to fulfil, but simply a comma-separated list of expressions to evaluate. All resulting values except from that of the last expression will be discarded. Hence, the boolean value of your < comparison is not used anywhere.

You can do something like this...
get_chat_server([], _) ->
undefined;
get_chat_server([Key|T], ChatServers) ->
{server, Pid, Reference,LoggedInUsers} = dict:fetch(Key,ChatServers),
if
LoggedInUsers < 100 ->
{server, Pid, Reference,LoggedInUsers};
true ->
get_chat_server(T, ChatServers)
end.
Or this
get_chat_server([], _) ->
undefined;
get_chat_server([Key|T], ChatServers) ->
Result = dict:fetch(Key,ChatServers),
case Result of
{_, _, _, LoggedInUsers} when LoggedInUsers < 100 ->
Result;
_ ->
get_chat_server(T, ChatServers)
end.

main_server_distributed.erl:66: Warning: this clause cannot match
because a previous clause at line 61 always matches
You've essentially written:
get_chat_server(NonEmptyList, ChatServers) ->
{server, Pid, Reference,LoggedInUsers} = dict:fetch(Key,ChatServers),
LoggedInUsers < 100,
{server, Pid, Reference,LoggedInUsers};
get_chat_server(NonEmptyList, ChatServers) ->
get_chat_server(T, ChatServers).
Therefore, the first clause will always match anything that the second clause would have matched. More specifically, in the pattern:
[Key|_]
Key will match anything and _ will match anything. Likewise, in the pattern:
[_|T]
_ will match anything, and T will match anything.
Riffing off #dsmith's answer:
-module(my).
-export([get_chat_server/3, get_chat_server_test/0]).
get_chat_server(_MaxLoggedIn, []=_Keys, _ChatServers) ->
none;
get_chat_server(MaxLoggedIn, [Key|Keys], ChatServers) ->
get_chat_server(MaxLoggedIn, Keys, ChatServers, dict:fetch(Key, ChatServers) ).
get_chat_server(MaxLoggedIn, _, _, {_,_,_,LoggedInUsers}=ChatServer) when LoggedInUsers < MaxLoggedIn ->
ChatServer;
get_chat_server(MaxLoggedIn, [Key|Keys], ChatServers, _ChatServer) ->
get_chat_server(MaxLoggedIn, Keys, ChatServers, dict:fetch(Key, ChatServers) ).
%---------
get_chat_server_test() ->
Keys = [a, c],
ChatServers = [
{a, {server, a, a_, 200}},
{b, {server, b, b_, 100}},
{c, {server, c, c_, 30}}
],
ChatServerDict = dict:from_list(ChatServers),
none = get_chat_server(10, [], ChatServerDict),
{server, c, c_, 30} = get_chat_server(50, Keys, ChatServerDict),
{server, c, c_, 30} = get_chat_server(150, Keys, ChatServerDict),
PossibleResults = sets:from_list([{server,a,a_, 200},{server,c,c_,30}]),
true = sets:is_element(
get_chat_server(250, Keys, ChatServerDict),
PossibleResults
),
all_tests_passed.
You can also use higher order functions, i.e. dict:fold(), to get a list of all the ChatServers that meet your requirements:
max_fun(Max, Keys) ->
fun(Key, {_,_,_,LoggedInUsers}=Server, Acc) ->
case lists:member(Key, Keys) andalso LoggedInUsers<Max of
true -> [Server | Acc];
false -> Acc
end
end.
In the shell:
44> ChatServers = [
44> {a, {server, a, a_, 200}},
44> {b, {server, b, b_, 100}},
44> {c, {server, c, c_, 30}}
44> ].
[{a,{server,a,a_,200}},
{b,{server,b,b_,100}},
{c,{server,c,c_,30}}]
45> ChatServerDict = dict:from_list(ChatServers).
{dict,3,16,16,8,80,48,
{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},
{{[],
[[a|{server,a,a_,200}]],
[[b|{server,b,b_,100}]],
[[c|{server,c,c_,30}]],
[],[],[],[],[],[],[],[],[],[],[],[]}}}
46> Keys = [a,c].
[a,c]
47> MaxLoggedIn = 150.
150
50> F = my:max_fun(MaxLoggedIn, Keys).
#Fun<fl.0.128553666>
51> dict:fold(F, [], ChatServerDict).
[{server,c,c_,30}]

Related

List of tuples [{id, [<List>]}, {id2, [<List>]} ] where ids are the second item of the tuple of the original list- Erlang

The title^ is kinda confusing but I will illustrate what I want to achieve:
I have:
[{<<"5b71d7e458c37fa04a7ce768">>,<<"5b3f77502dfe0deeb8912b42">>,<<"1538077790705827">>},
{<<"5b71d7e458c37fa04a7ce768">>,<<"5b3f77502dfe0deeb8912b42">>,<<"1538078530667847">>},
{<<"5b71d7e458c37fa04a7ce768">>,<<"5b3f77502dfe0deeb8912b42">>,<<"1538077778390908">>},
{<<"5b71d7e458c37fa04a7ce768">>,<<"5bad45b1e990057961313822">>,<<"1538082492283531">>
}]
I want to convert it to a list like this:
[
{<<"5b3f77502dfe0deeb8912b42">>,
[{<<"5b71d7e458c37fa04a7ce768">>,<<"5b3f77502dfe0deeb8912b42">>,<<"1538077790705827">>},
{<<"5b71d7e458c37fa04a7ce768">>,<<"5b3f77502dfe0deeb8912b42">>,<<"1538078530667847">>},
{<<"5b71d7e458c37fa04a7ce768">>,<<"5b3f77502dfe0deeb8912b42">>,<<"1538077778390908">>}
]},
{<<"5bad45b1e990057961313822">>,
[{<<"5b71d7e458c37fa04a7ce768">>,<<"5bad45b1e990057961313822">>,<<"1538082492283531">>}
]}
]
List of tuples [{id, [<List>]}, {id2, [<List>]} ] where ids are the second item of the tuple of the original list
Example :
<<"5b71d7e458c37fa04a7ce768">>,<<"5b3f77502dfe0deeb8912b42">>,<<"1538077790705827">>
Erlang newbie here. I created a dict with the second members of the tuples as keys and lists of corresponding tuples as values, then used dict:fold to transform it into the expected output format.
-export([test/0, transform/1]).
transform([H|T]) ->
transform([H|T], dict:new()).
transform([], D) ->
lists:reverse(
dict:fold(fun (Key, Tuples, Acc) ->
lists:append(Acc,[{Key,Tuples}])
end,
[],
D));
transform([Tuple={_S1,S2,_S3}|T], D) ->
transform(T, dict:append_list(S2, [Tuple], D)).
test() ->
Input=[{<<"5b71d7e458c37fa04a7ce768">>,<<"5b3f77502dfe0deeb8912b42">>,<<"1538077790705827">>},
{<<"5b71d7e458c37fa04a7ce768">>,<<"5b3f77502dfe0deeb8912b42">>,<<"1538078530667847">>},
{<<"5b71d7e458c37fa04a7ce768">>,<<"5b3f77502dfe0deeb8912b42">>,<<"1538077778390908">>},
{<<"5b71d7e458c37fa04a7ce768">>,<<"5bad45b1e990057961313822">>,<<"1538082492283531">>}
],
Output=transform(Input),
case Output of
[
{<<"5b3f77502dfe0deeb8912b42">>,
[{<<"5b71d7e458c37fa04a7ce768">>,<<"5b3f77502dfe0deeb8912b42">>,<<"1538077790705827">>},
{<<"5b71d7e458c37fa04a7ce768">>,<<"5b3f77502dfe0deeb8912b42">>,<<"1538078530667847">>},
{<<"5b71d7e458c37fa04a7ce768">>,<<"5b3f77502dfe0deeb8912b42">>,<<"1538077778390908">>}
]},
{<<"5bad45b1e990057961313822">>,
[{<<"5b71d7e458c37fa04a7ce768">>,<<"5bad45b1e990057961313822">>,<<"1538082492283531">>}
]}
] -> ok;
_Else -> error
end.
I think I see what you're after... Please correct me if I'm wrong.
There are a number of ways to do this, it really just depends on what sort of data structure you're interested in using to check the presence of like-keys. I'll show you two fundamentally different ways to do this and a third hybrid method that has become recently available:
Indexed data types (in this case a map)
List operations with matching
Hybrid matching over map keys
Since you're new I'll use the first case to demonstrate two ways of writing it: explicit recursion and using an actual list function from the lists module.
Indexy Data Types
The first way we'll do this is to use a hash table (aka "dict", "map", "hash", "K/V", etc.) and explicitly recurse through the elements, checking for the presence of the key encountered and adding it if it is missing, or appending to the list of values it points to if it does. We'll use an Erlang map for this. At the end of the function we'll convert the utility map back to a list:
explicit_convert(List) ->
Map = explicit_convert(List, maps:new()),
maps:to_list(Map).
explicit_convert([H | T], A) ->
K = element(2, H),
NewA =
case maps:is_key(K, A) of
true ->
V = maps:get(K, A),
maps:put(K, [H | V], A);
false ->
maps:put(K, [H], A)
end,
explicit_convert(T, NewA);
explicit_convert([], A) ->
A.
There is nothing wrong with explicit recursion (it is particularly good if you're new, because every part of it is left in the open to be examined), but this is a "left fold" and we already have a library function that abstracts a little bit of the plumbing out. So we really only need to write a function that checks for the presence of an element, and adds the key or appends the value:
fun_convert(List) ->
Map = lists:foldl(fun convert/2, maps:new(), List),
maps:to_list(Map).
convert(H, A) ->
K = element(2, H),
case maps:is_key(K, A) of
true ->
V = maps:get(K, A),
maps:put(K, [H | V], A);
false ->
maps:put(K, [H], A)
end.
Listy Conversion
The other major way we could have done this is with listy matching. To do that you need to first guarantee that your elements are sorted on the element you want to use as a key so that you can use it as a sort of "working element" and match on it. The code should be pretty easy to understand once you stare at it for a bit (maybe write out how it will step through your list by hand on paper once if you're totally perplexed):
listy_convert(List) ->
[T = {_, K, _} | Rest] = lists:keysort(2, List),
listy_convert(Rest, {K, [T]}, []).
listy_convert([T = {_, K, _} | Rest], {K, Ts}, Acc) ->
listy_convert(Rest, {K, [T | Ts]}, Acc);
listy_convert([T = {_, K, _} | Rest], Done, Acc) ->
listy_convert(Rest, {K, [T]}, [Done | Acc]);
listy_convert([], Done, Acc) ->
[Done | Acc].
Note that we split the list immediately after sorting it. The reason is that we have "prime the pump", so to speak, on the first call we make to listy_convert/3. This also means that this function will crash if you pass it an empty list. You can solve that by adding a clause to listy_convert/1 that matches on the empty list [].
A Final Bit of Magic
With those firmly in mind... consider that we also have a bit of a hybrid option available in newer versions of Erlang due to the magical syntax available to maps. We can match (most values) on map keys inside of a case clause (though we can't unify on a key value provided by other arguments within a function head):
map_convert(List) ->
maps:to_list(map_convert(List, #{})).
map_convert([T = {_, K, _} | Rest], Acc) ->
case Acc of
#{K := Ts} -> map_convert(Rest, Acc#{K := [T | Ts]});
_ -> map_convert(Rest, Acc#{K => [T]})
end;
map_convert([], Acc) ->
Acc.
Here is a one-liner that would produce your expected result:
[{K, [E || {_, K2, _} = E <- List, K =:= K2]} || {_, K, _} <- lists:ukeysort(2, List)].
What’s going on here? Let’s do it step by step…
This is your original list
List = […],
lists:ukeysort/2 leaves just one element per key in the list
OnePerKey = lists:ukeysort(2, List),
We then extract the keys with the first list comprehension
Keys = [K || {_, K, _} <- OnePerKey],
With the second list comprehension, we find the elements with the key…
fun Filter(K, List) ->
[E || {_, K2, _} = E <- List, K =:= K2]
end
Keep in mind that we can’t just pattern-match with K in the generator (i.e. [E || {_, K, _} = E <- List]) because generators in LCs introduce new scope for the variables.
Finally, putting all together…
[{K, Filter(K, List)} || K <- Keys]
It really depends on your dataset. For lager data sets using maps is a bit more efficient.
-module(test).
-export([test/3, v1/2, v2/2, v3/2, transform/1, do/2]).
test(N, Keys, Size) ->
List = [{<<"5b71d7e458c37fa04a7ce768">>,rand:uniform(Keys),<<"1538077790705827">>} || I <- lists:seq(1,Size)],
V1 = timer:tc(test, v1, [N, List]),
V2 = timer:tc(test, v2, [N, List]),
V3 = timer:tc(test, v3, [N, List]),
io:format("V1 took: ~p, V2 took: ~p V3 took: ~p ~n", [V1, V2, V3]).
v1(N, List) when N > 0 ->
[{K, [E || {_, K2, _} = E <- List, K =:= K2]} || {_, K, _} <- lists:ukeysort(2, List)],
v1(N-1, List);
v1(_,_) -> ok.
v2(N, List) when N > 0 ->
do(List,maps:new()),
v2(N-1, List);
v2(_,_) -> ok.
v3(N, List) when N > 0 ->
transform(List),
v3(N-1, List);
v3(_,_) -> ok.
do([], R) -> maps:to_list(R);
do([H={_,K,_}|T], R) ->
case maps:get(K,R,null) of
null -> NewR = maps:put(K, [H], R);
V -> NewR = maps:update(K, [H|V], R)
end,
do(T, NewR).
transform([H|T]) ->
transform([H|T], dict:new()).
transform([], D) ->
lists:reverse(
dict:fold(fun (Key, Tuples, Acc) ->
lists:append(Acc,[{Key,Tuples}])
end,
[],
D));
transform([Tuple={_S1,S2,_S3}|T], D) ->
transform(T, dict:append_list(S2, [Tuple], D)).
Running both with 100 unique keys and 100,000 records I get:
> test:test(1,100,100000).
V1 took: {75566,ok}, V2 took: {32087,ok} V3 took: {887362,ok}
ok

How to divide a string into substrings?

I would like to divide a string to sub-strings based on a given number , for example:
divide("string",1) = ["s","t","r","i","n","g"].
I have tried this, but no success .
lists:split(1,"string") = {"s", "tring"}
Any idea?
I would calculate the length once (since it's a slow operation) and then recursively use lists:split/2 until the list left is smaller than N:
divide(List, N) ->
divide(List, N, length(List)).
divide(List, N, Length) when Length > N ->
{A, B} = lists:split(N, List),
[A | divide(B, N, Length - N)];
divide(List, _, _) ->
[List].
1> c(a).
{ok,a}
2> a:divide("string", 1).
["s","t","r","i","n","g"]
3> a:divide("string", 2).
["st","ri","ng"]
4> a:divide("string", 3).
["str","ing"]
5> a:divide("string", 4).
["stri","ng"]
6> a:divide("string", 5).
["strin","g"]
7> a:divide("string", 6).
["string"]
8> a:divide("string", 7).
["string"]
I think #Dogbert solution is currently the best... But here an other implementation example with recursive loop.
divide_test() ->
[?assertEqual(divide("string",1), ["s","t","r","i","n","g"]),
?assertEqual(divide("string",2), ["st","ri","ng"]),
?assertEqual(divide("string",3), ["str","ing"]),
?assertEqual(divide("string",4), ["stri","ng"])
].
-spec divide(list(), integer()) -> list(list()).
divide(String, Size)
when is_list(String), is_integer(Size) ->
divide(String, Size, 0, [], []).
-spec divide(list(), integer(), integer(), list(), list()) -> list(list()).
divide([], _, _, Buf, Result) ->
Return = [lists:reverse(Buf)] ++ Result,
lists:reverse(Return);
divide([H|T], Size, 0, Buf, Result) ->
divide(T, Size, 1, [H] ++ Buf, Result);
divide([H|T], Size, Counter, Buf, Result) ->
case Counter rem Size =:= 0 of
true ->
divide(T, Size, Counter+1, [H] ++ [], [lists:reverse(Buf)] ++ Result);
false ->
divide(T, Size, Counter+1, [H] ++ Buf, Result)
end.
You can try this function. provided the number is > 0 less than or equal to string length divided by two.
first_substring(List, Separator) ->
first_substring_loop(List, Separator, []).
first_substring_loop([], _, Reversed_First) ->
lists:reverse(Reversed_First);
first_substring_loop(List, Separator, Reversed_First) ->
[H|T]= my_tuple_to_list(lists:split(Separator,List)),
first_substring_loop(lists:flatten(T), Separator, [H|Reversed_First]).
my_tuple_to_list(Tuple) -> [element(T, Tuple) || T <- lists:seq(1, tuple_size(Tuple))].
the result is
1> fact:first_substring("string", 1).
["s","t","r","i","n","g"]
2> fact:first_substring("string", 2).
["st","ri","ng"]
3> fact:first_substring("string", 3).
["str","ing"]
A short simple solution can be:
divide(String, Length) -> divide(String, Length, []).
divide([], _, Acc) -> Acc;
divide(String, Length, Acc) ->
{Res, Rest} = lists:split(min(Length, length(String)), String),
divide(Rest, Length, Acc ++ [Res]).
Also for a specific case of splitting with length 1, a list comprehension can be used:
ListOfLetters = [[Letter] || Letter <- String].

erlang ets select bad arg

erlang version 18.3
Got an strange error with Erlang ets:select/1
the following code will do select element from table and take them .
if I do
save(10), %% insert 10 data
remove(3) %% remove 3 data per time
it works
if I do
save(6007), %% insert more datas
remove(400) %% remove 400 data per time
it was bad arg in ets:select(Cont) also, it was not the in the first or second loop, but was always there.
any suggestion?
-record(item, {name, age}).
%% start the table
start() ->
ets:new(example_table, [public, {keypos, 2},
named_table,
{read_concurrency, true},
{write_concurrency, true}]).
%% insert n demo data
save(Limit) ->
All = lists:seq(1 ,Limit),
All_rec = [#item{name = {<<"demo">>, integer_to_binary(V)} , age = V} || V <- All],
ets:insert(example_table, All_rec).
%% remove all data, n data per select
remove(Limit) ->
M_head = #item{name = '$1', _ = '_'},
M_guards = [],
M_result = ['$1'],
M_spec = [{M_head, M_guards, M_result}],
case ets:select(example_table, M_spec, Limit) of
'$end_of_table' ->
0;
{Keys, Cont} ->
remove(example_table, Keys, Cont, 0, [])
end.
remove(Table, [], Cont, Count, _Acc) ->
case ets:select(Cont) of
'$end_of_table' ->
Count;
{Keys, Cont_1} ->
remove(Table, Keys, Cont_1, Count, [])
end;
remove(Table,[Key | T], Cont, Count, Acc) ->
case ets:take(example_table, Key) of
[] ->
remove(Table, T, Cont, Count, Acc);
[Rec] ->
io:format("Rec [~p] ~n", [Rec]),
remove(Table, T, Cont, Count + 1, [Rec | Acc])
end.
stack trace
4> example_remove:save(6007).
true
5> example_remove:remove(500).
** exception error: bad argument
in function ets:select/1
called as ets:select({example_table,304,500,<<>>,
[{<<"demo">>,<<"2826">>},
{<<"demo">>,<<"3837">>},
{<<"demo">>,<<"5120">>},
{<<"demo">>,<<"878">>},
{<<"demo">>,<<"1195">>},
{<<"demo">>,<<"1256">>},
{<<"demo">>,<<"1449">>},
{<<"demo">>,<<"5621">>},
{<<"demo">>,<<"5768">>}],
9})
in call from example_remove:remove/5 (d:/workspace/simple-cache/src/example_remove.erl, line 47)
I believe this happens because you simultaneously iterate over the table and modify it.
I suggest wrapping main remove cycle with guards of safe_fixtable
remove(Limit) ->
ets:safe_fixtable(example_table, true),
M_head = #item{name = '$1', _ = '_'},
M_guards = [],
M_result = ['$1'],
M_spec = [{M_head, M_guards, M_result}],
R = case ets:select(example_table, M_spec, Limit) of
'$end_of_table' ->
0;
{Keys, Cont} ->
remove(example_table, Keys, Cont, 0, [])
end,
ets:safe_fixtable(example_table, false),
R.

Erlang sumif function

I'm trying to make a sumif function in Erlang that would return a sum of all elements in a list if the predicate function evaluates to true. Here is what I have:
sumif(_, []) -> undefined;
sumif(Fun, [H|T]) -> case Fun(H) of
true -> H + sumif(Fun, T);
false -> sumif(Fun, T)
end.
I also implemented my own pos function which returns true if a number is greater than 0 and false otherwise:
pos(A) -> A > 0.
I tried using pos with sumif but I'm getting this error:
exception error: bad function pos
Why is this happening? Is it because of my sumif function or pos? I have tested pos on its own and it seems to work just fine.
Edit: It might be because how I'm calling the function. This is how I'm currently calling it: hi:sumif(pos,[-1,1,2,-3]). Where hi is my module name.
Is it because of my sumif function or pos?
It's because of sumif. You should return 0 when an empty list is passed, as it'll be called from the 2nd clause when T is []:
-module(a).
-compile(export_all).
sumif(_, []) -> 0;
sumif(Fun, [H|T]) -> case Fun(H) of
true -> H + sumif(Fun, T);
false -> sumif(Fun, T)
end.
pos(A) -> A > 0.
Test:
1> c(a).
{ok,a}
2> a:sumif(fun a:pos/1, [-4, -2, 0, 2, 4]).
6
List comprehensions make things far simpler:
sumif(F, L) ->
lists:sum([X || X <- L, F(X)]).
Dobert's answer is of cousrse right, problem is your sum for empty list.
If your concern is performance a little bit you should stick to tail recursive solution (in this case it matter because there is not lists:reverse/1 involved).
sumif(F, L) ->
sumif(F, L, 0).
sumif(F, [], Acc) when is_function(F, 1) -> Acc;
sumif(F, [H|T], Acc) ->
New = case F(H) of
true -> H+Acc;
false -> Acc
end,
sumif(F, T, New).
Ways how to make correct function for first parameter:
F1 = fun pos/1, % inside module where pos/1 defined
F2 = fun xyz:pos/1, % exported function from module xyz (hot code swap works)
N = 0,
F3 = fun(X) -> X > N end, % closure
% test it
true = lists:all(fun(F) -> is_function(F, 1) end, [F1, F2, F3]).
There has tow error in your code:
1. sumif(_, []) -> undefined; should return 0, not undefined.
2. when you pass pos(A) -> A > 0. to sumif/2,you should use fun pos/1, please read http://erlang.org/doc/programming_examples/funs.html#id59138
sumif(F, L) ->
lists:foldl(fun(X, Sum) when F(X) -> Sum+X; (_) -> Sum end, 0, L).
You can use lists:foldl.

Counting Number of Items in a tuple List in Erlang

I have the following List structure:
[{A, [{B <--, [A, C]}, {C <--, [B, A]}]}, {B, [{C <--, [A, C]}]}]
For example, B = 1, C = 2.
What would be the correct way to do so?
UPDATE
I'd like to count the number of <-- (a symbol I added just to show what I'm referring to) pointed item in it.
It can be implemented in many ways. Here is one more.
count(List) ->
count(List, dict:new()).
count([{_, InList} | Rest], Dict) ->
count(Rest, count2(InList, Dict));
count([], Dict) ->
dict:to_list(Dict).
count2([{Symbol, _} | Rest], Dict) ->
count2(Rest, dict:update_counter(Symbol, 1, Dict));
count2([], Dict) ->
Dict.
Example Output:
1> test:count([{one, [{b, [123]}, {c,[123]}, {b,[123]}]}, {two, [{b, [123]}, {c,[123]}, {b,[123]}]}]).
[{b,4},{c,2}]
You can write a simple code using an accumulator and some list functions. Supposing all list elements are of the same format:
count(L) ->
count (L, []).
count ([], Cases) ->
Cases;
count ([{_E1, [{X, [_E2, _E3]}]} | Rest], Cases) ->
NewCases =
case lists:keysearch(X, 1, Cases) of
false ->
[ {X, 1} | Cases ];
{value, {X, Val}} ->
lists:keyreplace(X, 1, Cases, {X, 1+Val})
end,
count(Rest, NewCases).

Resources