test with loop in erlang - erlang

I have a list of values ​​ "Z0010", "Z0011", "Z0012", "Z0013" "Z0014", "Z0015", "Z0016", "Z0017", "Z0018", "Z0019"
I want to develop a function that takes a value in parameter
and I want to do a test in my function if the value passed as a parameter is equal to a value in the list in this cases it will show "existe" if not it displays "not existe"
I try with :
test(Token)->
case get_user_formid_by_token(Token) of
{ok, H} ->
FormId=string:substr(H, 2, length(H)),
Form=string:to_integer(FormId),
case verify (0019,1,Form) of
{ok}->io:format("existe");
{notok}->io:format("not existe")
end;
{error, notfound}-> io:format("qq")
end.
verify(VariableLength,VariableIncrement,FormId)->
lists:map(fun(I) -> if I =:= FormId ->
{ok};
I =/= FormId ->
{notok}
end
end,
lists:seq(0010, VariableLength, VariableIncrement)).
but when I execute this code it displays :
1> model:test("21137900").
** exception error: no case clause matching [{notok},
{notok},
{notok},
{notok},
{notok},
{notok},
{notok},
{notok},
{notok},
{notok}]
in function model:test/1
I try now with this solution :
get_user_formid_by_token(Token) ->
Q = qlc:q([{X#person.formid} || X <- mnesia:table(person),
X#person.token =:= Token]),
case do(Q) of
[{H}] ->
{ok, H};
[] ->
{error, notfound}
end.
test(Token)->
case get_user_formid_by_token(Token) of
{ok, H} ->
io:format("~s~n",[H]),
FormId=string:substr(H, 5, length(H)),
io:format("~s~n",[FormId]),
Form=string:to_integer(FormId),
io:format("~p~n",[Form]),
lists:member(Form, lists:seq(313, 320, 1));
{error, notfound}-> io:format("qq")
end.
but when I test I have this message in the console:
1> model:test("21137900").
Z000313
313
{313,[]}
false
the result should be true and not false
I think that Form=string:to_integer(FormId), it not return in this case 313
and another thing I want to add in my code
for example if H equal "Z000010" FormId=string:substr(H, 2, length(H)),
it return "000010"
Now I want to eliminate the first zero before the first integer not null so extarct 0000
before 1

lists:map/2 takes one list and creates a new list with the same number of values, so your list of 10 values is transformed into a list of 10 {ok} or {notok} tuples.
You probably want lists:member/2 instead.
5> lists:member(0, lists:seq(1, 3, 1)).
false
6> lists:member(3, lists:seq(1, 3, 1)).
true
7> lists:map(fun(X) -> ok end, lists:seq(1, 3, 1)).
[ok,ok,ok]

Have a look at the documentation (http://www.erlang.org/doc/man/string.html#to_integer-1):
to_integer(String) -> {Int, Rest} | {error, Reason}
Types:
String = string()
Int = integer()
Rest = string()
Reason = no_integer | not_a_list
So to_integer returns a tuple containing the number that was consumed from the string and the rest of the string. You can even tell from your test output where it says {313,[]}. In order to get the value of the number bound to your Formvariable, you need to decompose the tuple, which is typically done by pattern matching:
{Form,_Rest}=string:to_integer(FormId)
Now your Form will contain only the number 313.
The string:to_integerfunction will also happily eat the leading zeroes:
1> {Form, _} = string:to_integer("000010"), Form.
10

Related

Exception error in function lists:foldl/3 (lists.erl, line 1263)

Question
Why when I run a function it works but when I pass it to lists:foldl it does not work?
Detailed explanation
When I run a specific function in the terminal, it returns the expected result. But if I pass this function to lists:foldl, it throws an exception.
The problematic function is separate_socks/2.
When I run it directly, it returns:
> sock_merchant:separate_socks(1, #{1 => [1]}).
#{1 => [1,1]}
> sock_merchant:separate_socks(1, #{}).
#{1 => [1]}
But when I run the test/0, it returns:
> sock_merchant:test().
** exception error: bad function separate_socks
in function lists:foldl/3 (lists.erl, line 1263)
My sock_merchant.erl file has the following content:
% John works at a clothing store. He has a large pile of socks that he must pair
% by color for sale. Given an array of integers representing the color of each
% sock, determine how many pairs of socks with matching colors there are.
% For example, there are `n = 7` socks with colors `ar = [1,2,1,2,1,3,2]`. There
% is one pair of color 1 and one of color 2. There are three odd socks left, one
% of each color. The number of pairs is 2.
-module(sock_merchant).
-export([count_number_of_pair_of_sockets/2,
filter_socks/2,
separate_socks/2,
sock_merchant/2,
test/0,
test_sock_merchant/0]).
%% Next: number
%% Acc: map
separate_socks(Next, Acc) ->
KeyExists = maps:is_key(Next, Acc),
case KeyExists of
true ->
CurrentKeyList = maps:get(Next, Acc),
maps:update(Next, [Next | CurrentKeyList], Acc);
false -> maps:put(Next, [Next], Acc)
end.
%% Value: number
filter_socks(_, Value) ->
if Value div 2 >= 1 -> true;
true -> false
end.
%% Next: {key, [number]}
%% Acc: number
count_number_of_pair_of_sockets({_, Arr}, Acc) ->
Acc + length(Arr) div 2.
%% N: number
%% Ar: [number]
sock_merchant(_, Ar) ->
% SocksSeparatedList = #{1: [1,1], 2: [2], ...}
SocksSeparatedList = lists:foldl(separate_socks,
#{},
Ar),
SocksWithPairs = maps:filter(filter_socks,
SocksSeparatedList),
ListOfSocksWithPairs = maps:to_list(SocksWithPairs),
lists:foldl(count_number_of_pair_of_sockets,
0,
ListOfSocksWithPairs).
test_sock_merchant() ->
3 = sock_merchant(9,
[10, 20, 20, 10, 10, 30, 50, 10, 20]),
pass.
test() -> pass = test_sock_merchant().
I'm solving this problem from HackerRank https://www.hackerrank.com/challenges/sock-merchant/problem?h_l=interview&playlist_slugs%5B%5D=interview-preparation-kit&playlist_slugs%5B%5D=warmup
The term separate_socks is, by itself, an atom. This means when you call lists:foldl/3 passing separate_socks as the first argument, you're just passing an atom, not a function as lists:foldl/3 requires:
SocksSeparatedList = lists:foldl(separate_socks,
#{},
Ar),
To instead pass the function separate_socks, pass it as a function term:
SocksSeparatedList = lists:foldl(fun separate_socks/2,
#{},
Ar),
The fun keyword indicates a function, and the trailing /2 is the function arity (its number of arguments).

write a function that, given a list, will drop every other element, starting by dropping the first element

Im working on some erlang functions and im also not allowed to use library functions. I have to define a function that drops every other element from a list, starting with the first element.
I have worked on something similar before but i could use BIFs and now i am struggling.
For example, alternate([1,2,3,four,5,6]) is [2,four,6]. I am not sure how to implement it.
spec drop_word(string()) -> string().
drop_word([]) -> [];
drop_word([O|Op]) -> case wsp(O) of
true -> Op;
false -> drop_word(Op)
end.
alternate(List) ->
alternate(List, _Index=0).
alternate([_|T], Index) when Index rem 2 == 0 -> %even indexes
alternate(T, Index+1);
alternate([H|T], Index) when Index rem 2 == 1 -> %odd indexes
[H | alternate(T, Index+1)];
alternate([], _Index) ->
[].
In the shell:
12> a:alternate([1,2,3,four,5,6]).
[2,four,6]
13> a:alternate([1,2,3,four,5]).
[2,four]
But, that can be simplified to:
alternate(List) ->
evens(List).
evens([_|T]) ->
odds(T);
evens([]) -> [].
odds([H|T]) ->
[H | evens(T)];
odds([]) -> [].
In the shell:
6> a:alternate([1,2,3,four,5,6]).
[2,four,6]
7> a:alternate([1,2,3,four,5]).
[2,four]
Here's an accumulator version:
alternate(List) ->
evens(List, []).
evens([_|T], Acc) ->
odds(T, Acc);
evens([], Acc) ->
lists:reverse(Acc).
odds([H|T], Acc) ->
evens(T, [H|Acc]);
odds([], Acc) ->
lists:reverse(Acc).
In the shell:
20> a:alternate([1,2,3,four,5,6]).
[2,four,6]
21> a:alternate([1,2,3,four,5]).
[2,four]
Note that lists:reverse() is highly optimized, so you would never do List ++ [X] many times, which traverses the whole list every time you add an element to the end of the list. Rather, you should always choose to add an element to the head of a list, then call lists:reverse(). Oh yeah, no library functions...a reverse() function is easy to implement yourself, and although it won't be optimized like the erlang version, it will still be more efficient than doing List ++ [X] multiple times.
You can use two atoms drop and keep two match the alternating clauses of do_alternate. Details below in comments.
-module(so).
-export([alternate/1]).
% The exported function starts the actual function and tells it to match the `drop`
% clause. Kept elements of L will be collected in the third argument.
alternate(L) -> do_alternate(drop, L, []).
% The `drop` clause will call the `keep` clause and pass the tail T and the
% currently collected list Acc. The head H will be dropped.
do_alternate(drop, [_|T], Acc) -> do_alternate(keep, T, Acc);
% The `keep` clause will call the `drop` claues and pass the tail T and the
% currently collected list Acc with the head H prepented to it.
do_alternate(keep, [H|T], Acc) -> do_alternate(drop, T, Acc ++ [H]);
% If the arugment list is empty, return the accumulated list.
do_alternate(_, [], Acc) -> Acc.
Example usage:
> c(so).
{ok,so}
9> so:alternate([1,2,3,4,5,6]).
[2,4,6]
10> so:alternate([1,2,3,4,5,6,seven,eight,nine,ten,eleven]).
[2,4,6,eight,ten]
It seems that you want to drop any elements with position which is even. So you can do it like below:
-module(test).
-compile([export_all,debug_info]).
alternate(L) -> do_alternate(L, 0, length(L)).
do_alternate(_, L, L) -> [];
do_alternate([H|T], N, L) ->
case (N band 1) == 0 of
true -> do_alternate(T, N+1, L);
false -> [H] ++ do_alternate(T, N+1, L)
end.
Result in shell:
1> c(test).
test.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,test}
2> test:alternate([1,2,3,four,5,6]).
[2,four,6]
Moreover, if your List only has integer numbers, so you can use BIF like below:
3> lists:partition(fun(A) -> A rem 2 == 1 end, [1,2,3,4,5,6]).
{[1,3,5],[2,4,6]}
You could pattern match on the list, taking two elements at a time:
alternate([_Odd, Even | T]) ->
[Even] ++ alternate(T);
alternate([]) ->
[].
The specification doesn't say what happens if the list has an odd number of elements, so this function will just crash with a "function clause" error in that case. You could add a third clause to handle that - presumably dropping the last element would be a sensible thing to do:
alternate([_Last]) ->
[];

How do you use foldl in erlang on a list of integers to return the maximum integer?

I would like to use the below Erlang code to get the highest integer in a list of integers but for some reason always end up getting the last integer in the list. Any help?
Solution example -> test:max([2,8,5,6]). should return 8 but with this code it returns 6.
-spec max(L) -> M when
L::[integer()],
M::integer().
max([H | T]) ->
F = fun(L, Acc) -> max([L]) end,
lists:foldl(F, H, T).
Your function F should return the max of L and Acc. You can use the builtin max/2 function for that:
...
F = fun(L, Acc) -> max(L, Acc) end.
...
Test:
1> F = fun(L, Acc) -> max(L, Acc) end.
#Fun<erl_eval.12.52032458>
2> [H | T] = [2, 8, 5, 6].
[2,8,5,6]
3> lists:foldl(F, H, T).
8
What you return in your function F will be the new value of Acc, and eventually the value lists:foldl/3 will return.
What you may want to do is do comparison inside F and check if Acc is greater than the current value. You don't need to recurse max/1 since you're iterating the list in lists:foldl/3 anyway.
Let me know if you need the actual code right away, but I would recommend figuring it out yourself. It's more fun for you that way.

Remove list element occur only once

I have a list in erlang containing interger values.
I want to remove values that occur only one time.(Not Duplicates).
Input = [1,3,2,1,2,2]
Output = [1,2,1,2,2]
I am newbie to erlang. I have tried an approach to sorting them first using list:sort() and then removing a member if the member next to it is the same.
I am having trouble trying to iterate the list. It would be great help if you can show me how I can do it.
multiple(L) ->
M = L -- lists:usort(L),
[X || X <- L , lists:member(X,M)].
Use map to count values and then filter values which was not present just once.
-module(test).
-export([remove_unique/1]).
remove_unique(L) ->
Count = lists:foldl(fun count/2, #{}, L),
lists:filter(fun(X) -> maps:get(X, Count) =/= 1 end, L).
count(X, M) ->
maps:put(X, maps:get(X, M, 0) + 1, M).
And test:
1> c(test).
{ok,test}
2> test:remove_unique([1,2,3,3,3,5,5,6,7,7]).
[3,3,3,5,5,7,7]
3> test:remove_unique([1,2,3,3,3,5,5,6,7,8]).
[3,3,3,5,5]
4> test:remove_unique([1,3,2,1,2,2]).
[1,2,1,2,2]
Here's a solution I'd written when first seeing the question when posted, that uses the same logic as #A.Sarid's recursion/pattern matching answer, except that I use a "Last" parameter instead of the count.
-module(only_dupes).
-export([process/1]).
process([]) -> [];
process(L) when is_list(L) ->
[H|T] = lists:sort(L),
lists:sort(process(undefined, H, T, [])).
process(Last, Curr, [], Acc)
when Curr =/= Last ->
Acc;
process(_Last, Curr, [], Acc) ->
[Curr | Acc];
process(Last, Curr, [Next | Rest], Acc)
when Curr =/= Last, Curr =/= Next ->
process(Curr, Next, Rest, Acc);
process(_Last, Curr, [Next | Rest], Acc) ->
process(Curr, Next, Rest, [Curr | Acc]).
One way for iterating a list (that as a result will return a new list) is using recursion and pattern matching.
After you sort your list you want to iterate the list and to check not only that it is different from the next element, but that there was no other equal elements before it. Consider the list [3,3,3,5,5] if you will only check the next element, the last 3 will also be unique and that is incorrect.
Here is a working program, I used a counter to cover the above case as well. See the syntax for using [H|T] for iterating over the list. You may see more cases and read more about it here.
-module(test).
-export([remove_unique/1]).
remove_unique(Input) ->
Sorted = lists:sort(Input),
remove_unique(Sorted, [], 0).
% Base case - checks if element is unique
remove_unique([H|[]],Output,Count) ->
case Count of
0 -> Output;
_Other -> [H|Output]
end;
% Count is 0 - might be unique - check with next element
remove_unique([H1|[H2|T]],Output, 0)->
case (H1 =:= H2) of
true -> remove_unique([H2|T],[H1|Output],1);
false -> remove_unique([H2|T],Output,0)
end;
% Count is > 0 - not unique - proceed adding to list until next value
remove_unique([H1|[H2|T]],Output,Count) ->
case (H1 =:= H2) of
true -> remove_unique([H2|T],[H1|Output],Count+1);
false -> remove_unique([H2|T],[H1|Output],0)
end.
Test
7> test:remove_unique([1,2,3,3,3,5,5,6,7,7]).
[7,7,5,5,3,3,3]
8> test:remove_unique([1,2,3,3,3,5,5,6,7,8]).
[5,5,3,3,3]

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.

Resources