exception error: no function clause - erlang

I have added the code as it stands. It can used on any piece of text I am doing some work in Erlang and I am getting an error message which I have included below.
exception error: no function clause matching string:to_lower({error,[80,75,3,4,20,0,6,0,8,0,0,0,33,0,2020], <<210,108,90,1,0,0,32,5,0,0,19,0,8,2,91,67,111,110,116,
101,110,116,95,84,121,...>>}) (string.erl, line 2084)
in function word_sort:readlines/1 (word_sort.erl, line 17).
I have also included an extract of my code below and I would appreciate if I could get pointers on where I am going wrong.
enter code here -module(word_sort).
enter code here-export([main/1]).
-export([unique/2]).
-export([sort/1]).
-export([readlines/1]).
-export([wordCount/3]).
% ========================================================== %
% Load the file and create a list %
% ========================================================== %
readlines(FileName) ->
io:format("~nLoading File : ~p~n", [FileName]),
{ok, File} = file:read_file(FileName),
Content = unicode:characters_to_list(File),
TokenList = string:tokens(string:to_lower(Content), " .,;:!?~/>'<{}£$%^&()#-=+_[]*#\\\n\r\"0123456789"),
main(TokenList).
% ========================================================== %
% Scan through the text file and find a list of unique words %
% ========================================================== %
main(TokenList) ->
UniqueList = unique(TokenList,[]),
io:format("~nSorted List : ~n"),
SortedList = sort(UniqueList), % Sorts UniqueList into SortedList%
io:format("~nSorted List : "),
io:format("~nWriting to file~n"),
{ok, F} = file:open("unique_words.txt", [write]),
register(my_output_file, F),
U = wordCounter(SortedList,TokenList,0),
io:format("~nUnique : ~p~n", [U]),
io:fwrite("~nComplete~n").
wordCounter([H|T],TokenList,N) ->
%io:fwrite("~p \t: ~p~n", [H,T]),
wordCount(H, TokenList, 0),
wordCounter(T,TokenList,N+1);
wordCounter([], _, N) -> N.
% =============================================================%
%Word count takes the unique word, and searches the original list for occurrences of that word%
%==============================================================%
wordCount(Word,[H|T],N) ->
case Word == H of % checks to see if H is in Seen List
true -> wordCount(Word, T, N+1); % if true, N_Seen = Seen List
false -> wordCount(Word, T, N) % if false, head appends Seen List.
end;
wordCount(Word,[],N) ->
io:fwrite("~p \t: ~p ~n", [N,Word]),
io:format(whereis(my_output_file), "~p \t: ~p ~n", [N,Word]).
%=================================================================================
unique([H|T],Seen) -> % Accepts List of numbers and Seen List
case lists:member(H, Seen) of % checks to see if H is in Seen List
true -> N_Seen = Seen; % if true, N_Seen = Seen List
false -> N_Seen = Seen ++ [H] % if false, head appends Seen List.
end,
unique(T,N_Seen); % calls uniques with Tail and Seen List.
%=================================================================================
unique([],Seen) -> Seen.
sort([Pivot|T]) ->
sort([ X || X <- T, X < Pivot]) ++
[Pivot] ++
sort([ X || X <- T, X >= Pivot]);
sort([]) -> [].

unicode:characters_to_list returned some error.
Variable 'Content' contains error message instead of data.
And string:to_lower() got error message as parameter instead of string.
You need just check what characters_to_list returns to you.
readlines(FileName) ->
io:format("~nLoading File : ~p~n", [FileName]),
{ok, File} = file:read_file(FileName),
case unicode:characters_to_list(File) of
Content when is_list(Content) ->
LCcontent = string:to_lower(Content),
TokenList = string:tokens(LCcontent,
" .,;:!?~/>'<{}£$%^&()#-=+_[]*#\\\n\r\"0123456789"),
main(TokenList);
Err ->
io:format("Cannot read file, got some unicode error ~p~n", [Err])
end.

Related

How to walk through directory in Erlang to take only folders?

-module(tut).
-export([main/0]).
main() ->
folders("C:/Users/David/test/").
folders(PATH) ->
{_,DD} = file:list_dir(PATH),
A = [{H,filelib:is_dir(PATH ++ H)}|| H <-DD],
% R is a list of all folders inside PATH
R = [PATH++X|| {X,Y} <- A, Y =:= true],
io:fwrite("~p~n", [R]),
case R of
[] -> ok;
% How call again folders function with the first element of the list?
% And save the result in some kind of structure
end.
Sorry for the beginner question, but I'm still new to Erlang. I would like to know how I can call the function again until saves the results in a kind of list, tuple or structure...
Like:
[
{"C:/Users/David/test/log",
{"C:/Users/David/test/log/a", "C:/Users/David/test/log/b"}},
{"C:/Users/David/test/logb",
{"C:/Users/David/test/logb/1", "C:/Users/David/test/logb/2","C:/Users/David/test/logb/3"}},
]
Few things:
These 2 calls can be simplified.
A = [{H,filelib:is_dir(PATH ++ H)}|| H <-DD],
R = [PATH++X|| {X,Y} <- A, Y =:= true],
into
A = [H || H <- DD, filelib:is_dir(PATH ++ H) =:= true],
In terms of representation, sub-folders should be in list format, not tuple. It will be difficult to work with if they were tuples.
Sample structure: {Folder, [Subfolder1, Subfolder2, ...]}, where SubfolderX will have the same definition and structure, recursively.
Folders are like tree, so need to have recursive call here. Hope you are already familiar with the concept. Below is one way to do it using list comprehension - there are other ways anyway, e.g. by using lists:foldl function.
folders(PATH) ->
{_, DD} = file:list_dir(PATH),
A = [H || H <- DD, filelib:is_dir(PATH ++ "/" ++ H) =:= true],
%%io:format("Path: ~p, A: ~p~n", [Path, A]),
case A of
[] -> %%Base case, i.e. folder has no sub-folders -> stop here
{PATH, []};
_ -> %%Recursive case, i.e. folder has sub-folders -> call #folders
{PATH, [folders(PATH ++ "/" ++ H2) || H2 <- A]}
end.
For consistency reason, you need to call the main function without a forward slash at the end, as this will be added in the function itself.
Folders = folders("C:/Users/David/test"). %% <- without forward slash
A helper function pretty_print below can be used to visualize the output on the Erlang shell
Full code:
-export([folders/1]).
-export([main/0]).
main() ->
Folders = folders("C:/Users/David/test"),
pretty_print(Folders, 0),
ok.
folders(PATH) ->
{_, DD} = file:list_dir(PATH),
A = [H || H <- DD, filelib:is_dir(PATH ++ "/" ++ H) =:= true], %%please note the "/" is added here
%%io:format("Path: ~p, A: ~p~n", [Path, A]),
case A of
[] -> %%Base case, i.e. folder has no sub-folders -> stop here
{PATH, []};
_ -> %%Recursive case, i.e. folder has sub-folders -> call #folders
{PATH, [folders(PATH ++ "/" ++ H2) || H2 <- A]}
end.
pretty_print(Folders, Depth) ->
{CurrrentFolder, ListSubfolders} = Folders,
SignTemp = lists:duplicate(Depth, "-"),
case Depth of
0 -> Sign = SignTemp;
_ -> Sign = "|" ++ SignTemp
end,
io:format("~s~s~n", [Sign, CurrrentFolder]),
[pretty_print(Subfolder, Depth+1) || Subfolder <- ListSubfolders].

Erlang inference

The following source doesn't compile because Stopover is unbound.
I'm new to Erlang, how can I rewrite it?
-module(distances).
-export([ path/2 ]).
path( madrid, paris ) ->
{ km, 1049 };
path( paris, moscou ) ->
{ km, 2482 };
path( moscou, berlin ) ->
{ km, 1603 };
path( From, To ) ->
path( From, Stopover ) + path( Stopover, To ).
The usage of this module maybe:
path( madrid, moscou ).
And the epected answer should be { km, 3531}.
The following source doesn't compile because Stopover is unbound.
I'm new to Erlang, how can I rewrite it?
Look at this code:
-module(a).
-compile(export_all).
do_stuff() ->
Stopover.
Here's what happens when I try to compile it:
a.erl:5: variable 'Stopover' is unbound
The variable Stopover was never assigned a value, so erlang has no idea what should be returned by the function do_stuff(). You are doing something similar here:
path( From, Stopover ) + path( Stopover, To ).
The variables From and To are parameter variables for the function path(), and when path() is called, e.g. path(madrid, moscow), then madrid will be assigned to the variable From, and moscow will be assigned to the variable To. Note, however, that nowhere do you assign any value to the variable Stopover.
You need to redefine path() to look like this:
path(From, To, Stopover) ->
Next, you should try to see if adding tuples actually works:
2> {km, 5} + {km, 3}.
** exception error: an error occurred when evaluating an arithmetic expression
in operator +/2
called as {km,5} + {km,3}
3>
Nope!
What you need to do is use pattern matching to extract the distance, an integer, from each tuple, then add the two integers:
{km, Distance1} = path( From, Stopover ),
... = path(Stopover, To),
{km, Distance1 + Distance2}.
This question is already answered by #7stud, and I was wondering how to implement such a path search in erlang. Here is a possible solution:
-module(distances).
-export([ path/2,getTowns/0,start/1, stop/0 ]).
path(From,To) ->
Paths = getPath(),
path(From,To,maps:get(orderedTuple(From,To), Paths, not_found),Paths).
% distanceServer in charge to keep the liste of known distances
% server interfaces
start(Towns) ->
{ok,List} = file:consult(Towns),
Paths = lists:foldl(fun({A,B,D},Acc) -> maps:put(orderedTuple(A,B), D, Acc) end,#{},List),
start(Paths,distance_server).
stop() ->
distance_server ! stop.
getTowns() ->
K = maps:keys(getPath()),
L = lists:usort(lists:flatten([[A,B] || {A,B} <- K])),
io:format("list of towns :~n~p~n~n",[L]).
getPath() ->
distance_server ! {getPath,self()},
receive
Path -> Path
end.
% server fuctions
start(Paths,Server) ->
Pid = spawn(fun() -> distanceServer(Paths) end),
register(Server, Pid).
distanceServer(Path) ->
receive
stop -> stop;
{getPath,From} ->
From ! Path,
distanceServer(Path)
end.
% Searching path
path(From,To,not_found,Paths) -> % if not in the known list, seach for the shortest path
{KM,P} = searchBestPath({0,[From]},To,maps:keys(Paths),{no_dist,no_path}),
case P of
no_path -> not_found;
_ -> {lists:reverse(P),KM}
end;
path(From,To,KM,_) -> % else give the result. Assumption: the known path contains always the best one.
{[From,To],KM}.
searchBestPath({N,[To|_]}=Path,To,_,{BestD,_}) when N < BestD -> Path; % keep the new path if it is better
searchBestPath({N,_},_,_,{BestD,_}=Best) when N >= BestD -> Best; % cancel search if the path so far is longer or equal to the best found
searchBestPath({D,[H|_]=PathSoFar},To,Remaining,Best) ->
Next = [remove(H,{A,B}) || {A,B} <- Remaining, (A =:= H) orelse (B =:= H)], % list of all possible next steps
case Next of
[] -> Best;
Next -> lists:foldl(
fun(X,Acc) ->
{_,ND} = path(H,X), % will always match
R = Remaining -- [orderedTuple(H,X)], % necessary to avoid possible infinite loop in the first search
searchBestPath({D+ND,[X|PathSoFar]},To,R,Acc) % evaluate path for all possible next steps
end,
Best,Next)
end.
% helpers
orderedTuple(A,B) when B > A -> {A,B};
orderedTuple(A,B) -> {B,A}.
remove(X,{X,B}) -> B;
remove(X,{A,X}) -> A.
it uses an external file to define the "known distances", I have used this one for test:
{paris,lyon,465}.
{lyon,marseille,314}.
{marseille,nice,198}.
{marseille,toulouse,404}.
{toulouse,bordeaux,244}.
{bordeaux,paris,568}.
{bordeaux,nantes,347}.
{nantes,paris,385}.
{paris,lille,225}.
{paris,strasbourg,491}.
{lille,strasbourg,525}.
{lille,bruxelles,120}.
{rennes,brest,244}.
{rennes,paris,351}.
{rennes,nantes,113}.
and the result in the shell:
1> c(distances).
{ok,distances}
2> distances:start("distances.txt").
true
3> distances:getTowns().
list of towns :
[bordeaux,brest,bruxelles,lille,lyon,marseille,nantes,nice,paris,rennes,
strasbourg,toulouse]
ok
4> distances:path(bordeaux,bruxelles).
{[bordeaux,paris,lille,bruxelles],913}
5> distances:path(nice,bruxelles).
{[nice,marseille,lyon,paris,lille,bruxelles],1322}
6> distances:path(moscou,paris).
not_found
7> distances:stop().
stop
8>
next step could be to increase the list of known distances each time a new request is done.

Cannot properly encode a sample text using huffman

The problem occurs in the find function where the erlang shell tells me that an exception error has occurred, it says:
Exception error: no function clause matching seminar1:find("t", []) (seminar1.erl, line 117) in function seminar1:encode/3 ( seminar1.erl, line 113).
I believe what is happening is that the pattern-matching done in the first find function is always failing, though I do not understand why since attempts to do comparisons manually have been successful.
-module(seminar1).
-compile(export_all).
sample() -> "the quick brown fox jumps over the lazy dog
this is a sample text that we will use when we build
up a table we will only handle lower case letters and
no punctuation symbols the frequency will of course not
represent english but it is probably not that far off".
text() -> "this is something that we should encode".
test() ->
Sample = sample(),
Tree = tree(Sample),
Encode = encode_table(Tree),
Decode = decode_table(Tree),
Text = text(),
Seq = encode(Text, Encode),
Text = decode(Seq, Decode).
tree(Sample) -> Freq = freq(Sample),
F = fun({node,N1,V1,_,_}, {node,N2,V2,_,_}) ->
if
V1 > V2 -> false;
V1 == V2 -> if
N1 > N2 -> false;
true -> true
end;
true -> true
end
end,
%lists:sort(F,Freq).
huffman(lists:sort(F,Freq)).
% Calculate the frequency of each letter in the Sample and return a
datastructure of nodes containing the letter involved,
% frequency of it in the sample.
% datastructure {node, Key, Value, Left, Right}
freq(Sample) -> freq(Sample, []).
freq([], Freq) -> Freq;
freq([Char|Rest], Freq) -> freq(Rest, check(Char, Freq)).
% Check function complements the Freq function, it takes the current input
and pattern matches it with the frequency datastructue being built.
% If it scores a hit that particular node has its frequency incremented and
then the whole datastructure is returned.
check(Key, []) -> [{node, [Key], 1, nil, nil}];
check(Key, [{node, [Key], Value, nil, nil}| Tail]) -> [{node, [Key], Value +
1, nil, nil}| Tail];
check(Key, [H|T]) -> [H |check(Key, T)].
% Creates the Huffman tree that is later used to encode a sample.
% The input is the SORTED datastructure derived from the freq-function.
% The leaves of the huffman tree are where actual values reside, branches
are just nodes containing information.
huffman( [ Tree | [] ] ) -> Tree;
huffman([{node, LeftKey, LeftValue, _L1, _R1},
{node, RightKey, RightValue, _L2, _R2} |Tail]) ->
% Creating a branch node
BranchNode = {node, LeftKey ++ RightKey, LeftValue + RightValue, {node,
LeftKey, LeftValue, _L1, _R1}, {node, RightKey, RightValue, _L2, _R2}},
huffman(insert(BranchNode, Tail)).
% A complementary function to the huffman function, inserts the newly made
branchnode into the already sorted tail.
% This is to prevent the sorted tail from becoming unsorted when turning the
tail list into a tree.
% It is inserted as such that the branchnode is the first selection of its
current value,
% meaning that if you have 4 nodes of value 5 ( one being a branchnode) then
the branch node will be the first option.
% This will make the Tree structure left leaning.
%
% N
% N N
% N N
% N N N N
insert(Node, []) -> [Node|[]];
insert(Node, [H|T]) ->
{_, _, Nvalue, _, _} = Node,
{_, _, Hdvalue, _, _} = H,
if
Nvalue =< Hdvalue -> [ Node | [H|T]];
true -> [H | insert(Node, T)]
end.
% Takes the tree created by the huffman-function as input and traverses said
tree.
% Returns a list containing the letters found and their position in the
tree, Left = 0, Right = 1.
% {"e"/[101], [0,0,0]} -- {[Key], [pathway]}
% Traversal method used: Left based traversal.
encode_table(RootNode) -> encode_table(RootNode, [], []).
% When traversing the Tree I need to know the branchnode I am in, the result
list as I am adding letters to it and a PathwayList which is the current
binary path to the branchnode I am in.
encode_table({_, Key, _, nil, nil}, AccList, PathwayList) ->
[AccList | [{Key, reverse(PathwayList)}]];
encode_table({_, _, _, Left, Right}, AccList, PathwayList) ->
encode_table(
Right,
encode_table(Left, AccList, [0| PathwayList]),
[1|PathwayList]).
% Complementary function for the encode_table/3 function, when traversing
the tree the the pathway gets reversed so it needs to be corrected.
reverse(L) -> reverse(L, []).
reverse([], Rev) -> Rev;
reverse([H|T], Rev) -> reverse(T, [H|Rev]).
% Takes a sample text and encodes it in accordance to the encoding table
supplied
encode(Text, Table) -> encode(Text, Table, []).
encode([], _, EncodedText) -> EncodedText;
encode([Letter|Rest], Table, EncodedText) ->
encode(Rest, Table, [find([Letter], Table) | EncodedText]).
% Complementary function to encode/3, searches the Table for the related
Letters binary path.
%find(Letter, []) -> Letter;
find(Letter, [{Letter, BinaryPath} | _Rest]) ->
BinaryPath;
find(Letter, [ _ | Rest]) ->
find(Letter, Rest).
decode_table(tree) -> ok.
decode(sequence, table) -> ok.
test(Letter, [{Letter, Asd} | []]) ->
true;
test(_, _) -> false.
I have tried to follow your code , but I am stuck on the function decode_table(tree) -> ok.. With this spelling, it fails (tree is an atom and won't match anything but tree itself). Change to _Tree to ignore the issue when I understood that the decode functions are not written yet or not provided.
For the encoding, the trouble is that the function encode_table returns a nested list, not suitable with the find function. If you replace the code by encode_table(RootNode) -> lists:flatten(encode_table(RootNode, [], [])). then it works (at least it seems to work since I don't know which result you are expecting)
-module(seminar1).
-compile(export_all).
sample() -> "the quick brown fox jumps over the lazy dog
this is a sample text that we will use when we build
up a table we will only handle lower case letters and
no punctuation symbols the frequency will of course not
represent english but it is probably not that far off".
text() -> "this is something that we should encode".
test() ->
Sample = sample(),
Tree = tree(Sample),
Encode = encode_table(Tree),
%Decode = decode_table(Tree),
Text = text(),
Seq = encode(Text, Encode),
%Text = decode(Seq, Decode).
Seq.
tree(Sample) -> Freq = freq(Sample),
F = fun({node,N1,V1,_,_}, {node,N2,V2,_,_}) ->
if
V1 > V2 -> false;
V1 == V2 -> if
N1 > N2 -> false;
true -> true
end;
true -> true
end
end,
%lists:sort(F,Freq).
huffman(lists:sort(F,Freq)).
% Calculate the frequency of each letter in the Sample and return a
% datastructure of nodes containing the letter involved,
% frequency of it in the sample.
% datastructure {node, Key, Value, Left, Right}
freq(Sample) -> freq(Sample, []).
freq([], Freq) -> Freq;
freq([Char|Rest], Freq) -> freq(Rest, check(Char, Freq)).
% Check function complements the Freq function, it takes the current input
% and pattern matches it with the frequency datastructue being built.
% If it scores a hit that particular node has its frequency incremented and
% then the whole datastructure is returned.
check(Key, []) ->
[{node, [Key], 1, nil, nil}];
check(Key, [{node, [Key], Value, nil, nil}| Tail]) ->
[{node, [Key], Value + 1, nil, nil}| Tail];
check(Key, [H|T]) ->
[H |check(Key, T)].
% Creates the Huffman tree that is later used to encode a sample.
% The input is the SORTED datastructure derived from the freq-function.
% The leaves of the huffman tree are where actual values reside, branches
% are just nodes containing information.
huffman( [ Tree | [] ] ) -> Tree;
huffman([{node, LeftKey, LeftValue, _L1, _R1},
{node, RightKey, RightValue, _L2, _R2} |Tail]) ->
% Creating a branch node
BranchNode = {node, LeftKey ++ RightKey, LeftValue + RightValue, {node, LeftKey, LeftValue, _L1, _R1}, {node, RightKey, RightValue, _L2, _R2}},
huffman(insert(BranchNode, Tail)).
% A complementary function to the huffman function, inserts the newly made
% branchnode into the already sorted tail.
% This is to prevent the sorted tail from becoming unsorted when turning the
% tail list into a tree.
% It is inserted as such that the branchnode is the first selection of its
% current value,
% meaning that if you have 4 nodes of value 5 ( one being a branchnode) then
% the branch node will be the first option.
% This will make the Tree structure left leaning.
%
% N
% N N
% N N
% N N N N
insert(Node, []) -> [Node|[]];
insert(Node, [H|T]) ->
{_, _, Nvalue, _, _} = Node,
{_, _, Hdvalue, _, _} = H,
if
Nvalue =< Hdvalue -> [ Node | [H|T]];
true -> [H | insert(Node, T)]
end.
% Takes the tree created by the huffman-function as input and traverses said tree.
% Returns a list containing the letters found and their position in the
% tree, Left = 0, Right = 1.
% {"e"/[101], [0,0,0]} -- {[Key], [pathway]}
% Traversal method used: Left based traversal.
encode_table(RootNode) -> lists:flatten(encode_table(RootNode, [], [])).
% When traversing the Tree I need to know the branchnode I am in, the result
% list as I am adding letters to it and a PathwayList which is the current
% binary path to the branchnode I am in.
encode_table({_, Key, _, nil, nil}, AccList, PathwayList) ->
[AccList | [{Key, reverse(PathwayList)}]];
encode_table({_, _, _, Left, Right}, AccList, PathwayList) ->
encode_table(
Right,
encode_table(Left, AccList, [0| PathwayList]),
[1|PathwayList]).
% Complementary function for the encode_table/3 function, when traversing
% the tree the the pathway gets reversed so it needs to be corrected.
reverse(L) -> reverse(L, []).
reverse([], Rev) -> Rev;
reverse([H|T], Rev) -> reverse(T, [H|Rev]).
% Takes a sample text and encodes it in accordance to the encoding table supplied
encode(Text, Table) -> encode(Text, Table, []).
encode([], _, EncodedText) -> EncodedText;
encode([Letter|Rest], Table, EncodedText) ->
encode(Rest, Table, [find([Letter], Table) | EncodedText]).
% Complementary function to encode/3, searches the Table for the related
% Letters binary path.
find(Letter, []) -> Letter;
find(Letter, [{Letter, BinaryPath} | _Rest]) ->
BinaryPath;
find(Letter, [ _ | Rest]) ->
find(Letter, Rest).
decode_table(_Tree) -> ok.
decode(sequence, table) -> ok.
test(Letter, [{Letter, _Asd} | []]) ->
true;
test(_, _) -> false.
gives the result:
64> c(seminar1).
{ok,seminar1}
65> rp(seminar1:test()).
[[0,0,0],
[1,0,0,0,1,0],
[0,1,1,1],
[1,0,1,1,0,0],
[0,1,0,0],
[0,0,0],
[1,1,1],
[1,0,0,0,1,0],
[1,0,0,1],
[1,1,0,1,0],
[0,1,1,1],
[1,0,1,0,0],
[0,1,0,1],
[1,1,1],
[0,0,0],
[1,0,1,0,1],
[1,1,1],
[1,1,0,0],
[0,0,1,1],
[1,0,1,0,0],
[1,1,0,0],
[1,1,1],
[1,0,0,0,0,0,0],
[0,1,0,0],
[1,1,0,1,1],
[1,0,1,0,0],
[1,1,0,0],
[0,0,0],
[1,0,0,0,1,1,1],
[0,1,1,1],
[0,1,0,1],
[1,1,1],
[0,1,0,1],
[1,1,0,1,1],
[1,1,1],
[0,1,0,1],
[1,1,0,1,1],
[1,0,1,0,0],
[1,1,0,0]]
ok
66>
Edit
You will get the same result if you replace
encode_table({_, Key, _, nil, nil}, AccList, PathwayList) ->
[AccList | [{Key, reverse(PathwayList)}]];
which is responsible for the nested result by this version which directly produces a flat list.
encode_table({_, Key, _, nil, nil}, AccList, PathwayList) ->
[{Key, reverse(PathwayList)} | AccList];
It is the general way to build a list: [Head|Tail] where Head is any erlang term and Tail is a list. Your code produces a result like [[[],{Key1,Path1}],{Key2,Path2}] while my version gives [{Key2,Path2},{Key1,Path1}]
Some remarks :
In erlang, the usage of if is not frequent, in my opinion mainly because of the last true -> DoSomething() clause which is in most cases very inexpressive.
Another point, searching in a list is not very fast, it is not an issue for isolate search, but in your case the encode and decode functions are doing it for each character, in my opinion, a map is more appropriate to store the Encode and Decode tables than a key/value list.

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.

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?
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.
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).
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.
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}]
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).

Resources