Adding to an existing value in Erlang - erlang

I am attempting to create a function that stores a number into a record and then adds value X to that number every time the function runs.
Value: 5
Run Function (Add One): 1
Value should be: 6
Run Function (Add One): 1
value should be 7
I tried to use a record:
-record(adder,{value :: integer()}).
---function
Number = random:uniform(6),
L=#added{value = Number + #added.value}.
This does not work as it resets the value every time. Any suggestions?

Take a look at this code:
-module(test).
-export([add/1]).
-record(adder, {value=6}).
add(X) ->
#adder{value = X + #adder.value}.
If you compile this in your shell, any call to "add(3)" will result in "{adder,5}" and not in "{adder, 9}". Take a look:
Eshell V6.4 (abort with ^G)
1> c(test).
{ok,test}
2> test:add(3).
{adder,5}
3> test:add(3).
{adder,5}
How come? This is because records are actually tuples. The expression "#adder.value" in the last line is evaluated as the position of the field "value" in your adder tuple, which is 2. Let's have some proof. Change the definition of your record:
-module(test).
-export([add/1]).
-record(adder, {field1, field2, value=6}).
add(X) ->
#adder{value = X + #adder.value}.
Now, recompiling your code and calling add(3) again would result in
1> c(test).
{ok,test}
2> test:add(3).
{adder,undefined,undefined,7}
I've asked myself, how you came up with this question. Didn't you want your function to be something like this?
add2(#adder{value = V} = R, X) ->
R#adder{value = V + X}.

-record(adder, {value = 5}).
add(Value) ->
add(#adder{}, Value).
add(#adder{value =V} = Adder, Value) ->
Adder#adder{value = V + Value}.
test() ->
R1 = add(1),
io:format("~p~n", [R1]),
R2 = add(R1, 10),
io:format("~p~n", [R2]).
Here is the output of running test:test().
6> c(test).
{ok,test}
7> test:test().
{adder,6}
{adder,16}
ok

Related

Erlang: How do you return an element of a list?

For example: [{a,b},{c,d},{e,f}]. I want to pick on the list with an argument (being c) and it will return d.
You can use few approaches or use Erlang functions from the standard library(like lists etc.) or you can create your own, eg:
List Comprehensions
1> List = [{a,b}, {c,d}, {e,f}].
2> Being = e.
3> [Result] = [Y || {X, Y} <- List, Being =:= X].
4> Result.
f
Functions
1> GetVal = fun GetVal (_, []) -> not_found;
GetVal (X, [{X, Result} | _]) -> Result;
GetVal (X, [_ | T]) -> GetVal(X, T)
end.
2> List = [{a,b}, {c,d}, {e,f}].
3> Being = e.
4> GetVal(Being, List).
f
The simple way to use Pattern Matching and List Handling.
Write a program that prints each tuple in the list.
Write a program that prints just the second element of each tuple in the list.
Write a program that takes an argument Target along with a List. When you find the tuple {Target, Right}, print our Right.
If you don't mind using functions from the standard library, you can use lists:keyfind/2 or proplists:get_value/2,3.

Trying to compare the each element of a list with the keys of a Map [I tried with the following code]

I tried the code below , whereas the M1 is the Map consists of M1= #{a =>"Apple",b =>"Ball"}, and Str is the given by user ex: fun("ab").
I want to print the relevant value of the key in Map M1 based on the given string Str.
Tried Code:
fun(Str) ->
X = [ [X] || X <- Str],
Key = maps:keys(M1),
mOrse_convert(X,Key)
end;
mOrse_convert([],Key) ->
true;
mOrse_convert([First|Rest],Key) ->
case Key of
#{ X := A} -> A
end
mOrse_convert(Rest,Key)
end.
Can anyone help/suggest me ?
This function has 2 arguments: Str - value to find and target Map. The function returns list of all keys in Map that have value equals Str.
-module(ex).
-export([func/2]).
func(Str, Map) ->
Fun = fun(K, V, Acc) ->
if V == Str -> [K | Acc];
true -> Acc
end
end,
maps:fold(Fun, [], Map).
Go to Erlang shell and type following command:
1> c("ex.erl").
{ok,ex}
2> ex:func("a", #{1 => "a", 2 => "b", 3 => "ab"}).
[1]
3> ex:func("a", #{1 => "a", 2 => "b", 3 => "ab", 4 => "a"}).
[4,1]
Thank you Alexei , the solution provided by you is working good for an alphabet and got the output only for single character and given below, but I want to pass the List as input in as Str , I tried the below code as List as input,
Output for single alphabet :
20> c(morse).
{ok,morse}
21> morse:morse_convert("s").
Single ok
My Required output is :
20> c(morse).
{ok,morse}
21> morse:morse_convert("abc").
Apple Ball Cat ok
Tried Code :
X = [ [X] || X <- Str],
Y = func(X,Morse),
io:format(Y ).
func([],{}) -> io:fwrite("\nCompleted.\n");
func([First | Last], Morse) ->
Fun = fun(K, V, Acc) ->
if K == First -> [V | Acc];
true -> Acc
end
end,
maps:fold(Fun, [], Morse),
func(Last,Morse).
-module(a).
-compile(export_all).
cypher() ->
#{"a" =>"Apple",
"b" => "Ball",
"c" => "Cat"}.
convert([]) -> io:format("~n");
convert([Int|Ints]) ->
Word = maps:get([Int], cypher()),
io:format("~s ", [Word]),
convert(Ints).
In the shell:
~/erlang_programs$ erl
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V9.3 (abort with ^G)
1> c(a).
a.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,a}
2> a:convert("abc").
Apple Ball Cat
ok
3>
An erlang string, e.g. "abc", is actually a shortcut for creating a list of integers, where each integer is the ascii code of a letter in the string. For example:
3> "abc" =:= [97,98,99].
true
When the shell outputs a string, the shell expects you to know that the string is really a list of integers, which is confusing. To eliminate that confusion, you can tell the shell not to output strings by executing the function shell:strings(false):
5> "abc".
"abc"
6> shell:strings(false).
true
7> "abc".
[97,98,99]
Then you can see what you are really dealing with.
Next, when you use pattern matching to remove an integer from a list, you have an integer--not a string. To create a string from an integer, you need to put the integer into a list:
[Int]
You can see that here:
2> 97 =:= "a".
false
3> [97] =:= "a".
true
It's not clear whether you have atoms or strings as the keys in your map or whether you don't care. If your map must have atoms as the keys, you can convert strings to atoms using list_to_atom/1:
8> list_to_atom([97]).
a
Finally, when you want to output a string, e.g. one of the values in the map, rather than a list (after executing shell:strings(false)), you can use the ~s formatting sequence:
16> io:format("~s~n", ["Apple"]).
Apple
ok
Using a list comprehension would look like this:
convert(Str) ->
Cypher = #{"a" =>"Apple",
"b" => "Ball",
"c" => "Cat"
},
[
io:format("~s ", [maps:get([Int], Cypher)] )
|| Int <- Str
],
io:format("~n").
A list comprehension always returns a list, in this case [ok, ok, ok], which is not something you care about--you only care about the side affect of outputting the values. So, you can ignore the list and return something else, i.e. whatever io:format/1 returns, which is ok.
Remember, it's less confusing to have the shell output lists rather than strings, then only output strings when you specifically tell the shell to do it.
I was not sure to understand what you are looking for, here are 2 interpretations.
1> M = #{a =>"Apple",b =>"Ball",c=>"Corn",d=>"Donut",e=>"Ball"}.
#{a => "Apple",b => "Ball",c => "Corn",d => "Donut",
e => "Ball"}
2> L = ["Ball","Donut"].
["Ball","Donut"]
3> % first, get list of keys from list of values: expected result = [b,d,e]
3> [K || {K,V} <- maps:to_list(M), lists:member(V,L) == true].
[b,d,e]
4> L1 = "ace".
"ace"
5> % second, get list of values from list of keys: expected result ["Apple","Corn","Ball"]
5> [maps:get(list_to_atom([X]),M) || X <- L1].
["Apple","Corn","Ball"]
6>

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.

List replication challenge with Erlang

I'm trying to study Erlang resolving Hackerrank problems. There is a problem called List Replication. I finished with a solution like this:
-module(solution).
-export([main/0]).
process_input(Repeats)->
Line = io:get_line(""),
case string:len(Line) of
1 -> ok;
_ -> output(Line, Repeats), process_input(Repeats)
end.
output(_, 0)-> ok;
output(Line, Repeats)->
io:format(Line),
output(Line, Repeats - 1).
main()->
{ok, [Repeats]} = io:fread("", "~d"),
process_input(Repeats).
But this solution has a problem: I expect the last line is empty (in fact the last line is a number without \n). Any thoughts?
I think it's easier to handle eof from io:get_line/1 in case of a missing final newline, as well as handling a blank line to indicate end of input:
-module(solution).
-export([start/0]).
process_input(Repeat, Acc)->
case io:get_line("") of
Done when Done == eof; Done == "\n" ->
output(lists:reverse(Acc));
Line ->
Val = string:strip(Line, right, $\n),
Str = lists:duplicate(Repeat, Val),
process_input(Repeat, [Str|Acc])
end.
output(Lines)->
Out = [string:join(L, "\n")++"\n" || L <- Lines],
io:format("~s", [Out]).
start()->
{ok, [Repeat]} = io:fread("", "~d"),
process_input(Repeat, []).
The process_input/2 function now takes an accumulator, which is initially an empty list. It calls itself recursively until it detects end of input, after which it prints the output. It calls io:get_line/1 and checks to see if it returns either eof or just a newline, and for that case it reverses its accumulator and prints its output. For any other input, it strips the final newline, repeats the input via lists:duplicate/2, stores the result in a new accumulator, and passes that to a recursive call.
The output/1 function takes the accumulator from process_input/2, joins the repeated values with newlines, then prints the results. Note that this version of the solution module restricts the formatting of the result to the output/1 function, in case you wanted to use the raw result of process_input/2 for some other purpose.
And finally, I renamed your main/0 to start/0 because running a function via the erl -s command line option assumes a function named start if none is given.
We can use printf in a Unix shell to create an input file without a final newline:
$ printf '3\n1\n2\n3\n4\n' > in
and then run our compiled solution module like this, getting the tripled output we expect in this case:
$ cat in | erl -noshell -s solution -s init stop
1
1
1
2
2
2
3
3
3
4
4
4
Adding a final newline to the in file gives the same result (try it). We can also create input with more than a single character per line:
$ printf '2\nhey\nhey\nwhat\ncan\nI\ndo' > in2
$ cat in2 | erl -noshell -s solution -s init stop
hey
hey
hey
hey
what
what
can
can
I
I
do
do
and for this in2 file, we get the doubled output we expect as well.
You will have to turn off the echo of the stream, with io:setopts/1
-module(solution).
-export([main/0]).
process_input(Repeats)->
Line = string:strip(io:get_line(""), right, $\n),
case string:len(Line) of
0 ->
ok;
_ ->
output(Line, Repeats),
process_input(Repeats)
end.
output(_, 0)->
ok;
output(Line, Repeats)->
io:format("~s\n", [Line]),
output(Line, Repeats - 1).
main()->
{ok, [Repeats]} = io:fread("", "~d"),
io:setopts([{echo, false}]),
process_input(Repeats).
I just updated the code which solves the challenge, so the idea is that you save the input in an accumulator (a list in this case) and at the end you process the list, if you want to avoid the output of what is being written on screen at any moment you can disable the echo as the example I show on the other answer
-module(solution).
-export([main/0]).
process_input(Data)->
Number = io:get_line(""),
case string:len(Number) of
1 ->
Data;
_ ->
process_input(Data ++ [Number])
end.
process_output([], _)->
ok;
process_output([H|Data], Repeats)->
print(H, Repeats),
process_output(Data, Repeats).
print(_, 0) ->
ok;
print(Element, Times) ->
io:format(Element),
print(Element, Times - 1).
main()->
{ok, [Repeats]} = io:fread("", "~d"),
Data = process_input([]),
process_output(Data, Repeats).
And the test:
rorra:~/erlang > erl
Erlang/OTP 17 [erts-6.4] [source] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V6.4 (abort with ^G)
1> c(solution).
{ok,solution}
2> solution:main().
3
1
2
3
4
1
1
1
2
2
2
3
3
3
4
4
4
ok
3>
My own answer:
-module(solution).
-export([main/0]).
process_input(Repeats)->
Line = io:get_line(""),
case lists:reverse(Line) of
"\n" ++ _ -> output(Line, Repeats), process_input(Repeats);
_ -> output(Line ++ "~n" , Repeats)
end.
output(_, 0)-> ok;
output(Line, Repeats)->
io:format(Line),
output(Line, Repeats - 1).
main()->
{ok, [Repeats]} = io:fread("", "~d"),
process_input(Repeats).
Here's what I came up with (with help from the answers above). I'm adding my solution because it also handles the constraints stated in the problem:
-module(solution).
-export([main/0]).
main() -> get_input([]).
print_list(_,[_|[]]) -> ok;
print_list(NumTimes,[_|List]) ->
Number = hd(List),
print_list_number(NumTimes,Number),
print_list(NumTimes,List).
print_list_number(NumTimes,Number)
when
(NumTimes > 0)
and
(Number >= 1)
and
(Number =< 100)
->
io:fwrite("~B~n",[Number]),
print_list_number(NumTimes - 1,Number);
print_list_number(_,_) -> ok.
get_input(Acc) ->
case io:get_line("") of
Done when
Done == eof;
Done == "\n"
->
NumTimes = hd(Acc),
%% Make sure we only run this when the List length isn't greater than 10
if
(length(Acc) - 1 =< 10)
and
(NumTimes =< 100)
->
print_list(NumTimes,Acc);
true -> ok
end;
Line ->
{NumInt,_} = string:to_integer(Line),
List = Acc ++ [NumInt],
get_input(List)
end.
I'm pretty new to Erlang so forgive me if this is messy / inefficient!

Shuffling Elements in a List (randomly re-arrange List Elements)

Part of my program requires me to be able to randomly shuffle list elements. I need a function such that when i give it a list, it will pseudo-randomly re-arrange the elements in the list. A change in arrangement Must be visible at each call with the same list. My implementation seems to work just fine but i feel that its rather long and is increasing my code base and also, i have a feeling that it ain't the best solution for doing this. So i need a much shorter implementation. Here is my implementation:
-module(shuffle).
-export([list/1]).
-define(RAND(X),random:uniform(X)).
-define(TUPLE(Y,Z,E),erlang:make_tuple(Y,Z,E)).
list(L)->
Len = length(L),
Nums = lists:seq(1,Len),
tuple_to_list(?TUPLE(Len,[],shuffle(Nums,L,[]))).
shuffle([],_,Buffer)-> Buffer;
shuffle(Nums,[Head|Items],Buffer)->
{Pos,NewNums} = pick_position(Nums),
shuffle(NewNums,Items,[{Pos,Head}|Buffer]).
pick_position([N])-> {N,[]};
pick_position(Nos)->
T = lists:max(Nos),
pick(Nos,T).
pick(From,Max)->
random:seed(begin
(case random:seed(now()) of
undefined ->
NN = element(3,now()),
{?RAND(NN),?RAND(NN),?RAND(NN)};
Any -> Any
end)
end
),
T2 = random:uniform(Max),
case lists:member(T2,From) of
false -> pick(From,Max);
true -> {T2,From -- [T2]}
end.
On running it in shell:
F:\> erl
Eshell V5.8.4 (abort with ^G)
1> c(shuffle).
{ok,shuffle}
2> shuffle:list([a,b,c,d,e]).
[c,b,a,e,d]
3> shuffle:list([a,b,c,d,e]).
[e,c,b,d,a]
4> shuffle:list([a,b,c,d,e]).
[a,b,c,e,d]
5> shuffle:list([a,b,c,d,e]).
[b,c,a,d,e]
6> shuffle:list([a,b,c,d,e]).
[c,e,d,b,a]
I am motivated by the fact that in the STDLIB there is no such function. Somewhere in my game, i need to shuffle things up and also i need to find the best efficient solution to the problem, not just one that works.
Could some one help build a shorter version of the solution ? probably even more efficient ? Thank you
1> L = lists:seq(1,10).
[1,2,3,4,5,6,7,8,9,10]
Associate a random number R with each element X in L by making a list of tuples {R, X}. Sort this list and unpack the tuples to get a shuffled version of L.
1> [X||{_,X} <- lists:sort([ {random:uniform(), N} || N <- L])].
[1,6,2,10,5,7,9,3,8,4]
2>
Please note that karl's answer is much more concise and simple.
Here's a fairly simple solution, although not necessarily the most efficient:
-module(shuffle).
-export([list/1]).
list([]) -> [];
list([Elem]) -> [Elem];
list(List) -> list(List, length(List), []).
list([], 0, Result) ->
Result;
list(List, Len, Result) ->
{Elem, Rest} = nth_rest(random:uniform(Len), List),
list(Rest, Len - 1, [Elem|Result]).
nth_rest(N, List) -> nth_rest(N, List, []).
nth_rest(1, [E|List], Prefix) -> {E, Prefix ++ List};
nth_rest(N, [E|List], Prefix) -> nth_rest(N - 1, List, [E|Prefix]).
For example, one could probably do away with the ++ operation in nth_rest/3. You don't need to seed the random algorithm in every call to random. Seed it initially when you start your program, like so: random:seed(now()). If you seed it for every call to uniform/1 your results become skewed (try with [shuffle:list([1,2,3]) || _ <- lists:seq(1, 100)]).
-module(shuffle).
-compile(export_all).
shuffle(L) ->
shuffle(list_to_tuple(L), length(L)).
shuffle(T, 0)->
tuple_to_list(T);
shuffle(T, Len)->
Rand = random:uniform(Len),
A = element(Len, T),
B = element(Rand, T),
T1 = setelement(Len, T, B),
T2 = setelement(Rand, T1, A),
shuffle(T2, Len - 1).
main()->
shuffle(lists:seq(1, 10)).
This will be a bit faster than the above solution, listed here as do2 for timing comparison.
-module(shuffle).
-export([
time/1,
time2/1,
do/1,
do2/1
]).
time(N) ->
L = lists:seq(1,N),
{Time, _} = timer:tc(shuffle, do, [L]),
Time.
time2(N) ->
L = lists:seq(1,N),
{Time, _} = timer:tc(shuffle, do2, [L]),
Time.
do2(List) ->
[X||{_,X} <- lists:sort([ {rand:uniform(), N} || N <- List])].
do(List) ->
List2 = cut(List),
AccInit = {[],[],[],[],[]},
{L1,L2,L3,L4,L5} = lists:foldl(fun(E, Acc) ->
P = rand:uniform(5),
L = element(P, Acc),
setelement(P, Acc, [E|L])
end, AccInit, List2),
lists:flatten([L1,L2,L3,L4,L5]).
cut(List) ->
Rand=rand:uniform(length(List)),
{A,B}=lists:split(Rand, List),
B++A.

Resources