I'm new in the Erlang world. I'm trying to implement the function split_binary. The function takes as input (list, index) and it splits the list in two lists according to the index.
split(Lst, N) when N>=list:lenght(Lst) -> Lst;
split(Lst, N) when N<list:lenght(Lst) -> splitHelper(list:reverse(Lst), 0, N, []).
splitHelper([H|T], X, N, Acc) ->
if
X>=N ->
(list:reverse([H|T]), list:reverse(Acc));
X<N ->
splitHelper(T, X+1, N, [H|Acc])
end.
How can I improve my code?
I'm new in the Erlang world. I'm trying to implement the function
split_binary. The function takes as input (list, index) and it splits
the list in two lists according to the index.
According to the erlang docs for split_binary/2, the two arguments are a binary, which is not a list, and the number of bytes where you want to split the binary.
First, you need to have a basic understanding of what a binary is. A binary is a sequence of bytes, where each byte is 8 bits representing some integer, e.g.
0010 0001
which is 33. Here is an example of a binary:
<<1, 2, 3>>
When you don't specify a size for each integer, by default each integer will occupy one byte. If you wanted the 2 to occupy two bytes instead, i.e. 0000 0000 0000 0010, which is 16 bits, then you could write:
<<1, 2:16, 3>>
which the shell would display as:
<<1,0,2,3>>
Huh? Where did that 0 come from? The shell displays a binary byte by byte, and the first byte of the integer 0000 0000 0000 0010 is 0000 0000, which is 0.
Next, you can step through a binary just like you can for a list, extracting any number of bits at a time from the front of the binary. It so happens that split_binary/2 extracts 8 bits, or 1 byte, at a time from the head of the binary.
There are a couple of tricks to learning how to step through a binary:
For lists, [] means an empty list, and for binaries <<>> means an empty binary.
For lists you write [Head|Tail] to extract the head of the list, and for binaries you write <<Bits:3, Rest/binary>> to extract 3 bits from the front of the binary. In your case, you need to extract 8 bits from the front of the binary.
Here is an example of what you can do:
-module(a).
-compile(export_all).
split_b(Bin, N) ->
split_b(Bin, N, _Acc = <<>>).
split_b( Bin, _N = 0, Acc) -> [Acc, Bin];
split_b(<<Bits:8, Rest/binary>>, N, Acc) ->
split_b(Rest, N-1, <<Acc/binary, Bits>>).
In the shell:
40> c(a).
a.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,a}
41> a:split_b(<<5,6,7>>, 1).
[<<5>>,<<6,7>>]
42> a:split_b(<<5,6,7>>, 2).
[<<5,6>>,<<7>>]
Note that when constructing a binary one of the segments of the binary can be another binary:
23> Bin = <<1, 2, 3>>.
<<1,2,3>>
24> Acc = <<Bin/binary, 4>>.
<<1,2,3,4>>
If you are actually trying to implement lists:split/2, you can do this:
-module(a).
-compile(export_all).
split_l(N, List) ->
split_l(N, List, _Acc=[]).
split_l(_N=0, List, Acc) ->
[lists:reverse(Acc), List];
split_l(N, [H|T], Acc) ->
split_l(N-1, T, [H|Acc]).
In the shell:
2> c(a).
a.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,a}
3> a:split_l(1, [10, 20, 30]).
["\n",[20,30]]
4> shell:strings(false).
true
5> a:split_l(1, [10, 20, 30]).
[[10],[20,30]]
6> a:split_l(2, [10, 20, 30]).
[[10,20],[30]]
I think #7stud's answer is the best one, but I wanted to add a few minor details about your code, without actually checking if it works or not…
list:lenght/1 doesn't exist (unless you also created your own list module.
If you created your own list module, you can't use it in guards. Only BIFs are allowed there.
If you're trying to use stdlib's function to check the length of a list, then you should use erlang:length/1 or just length/1.
It's more idiomatic in Erlang to use snake_case (e.g. split_helper) instead of camelCase (e.g. splitHelper) for module names, function names and atoms in general.
You can use pattern-matching directly instead of writing an if as the sole expression of your function…
split_helper([H|T], X, N, Acc) when X > N ->
(list:reverse([H|T]), list:reverse(Acc));
split_helper([H|T], X, N, Acc) when X<N ->
split_helper(T, X+1, N, [H|Acc]).
Tuples are denoted with curly braces and not parentheses: {list:reverse([H|T]),…. BTW… This should have prevented your code from compiling at all. The error should've looked like syntax error before: ','
Also, you might have written your own list module, but if not and if you're trying to use stdlib functionality, it's lists:reverse/1 not list:reverse/1.
Finally, out of that list, I would strongly recommend you to write some simple tests for your code. This article may help you with that.
Related
I have a task: "Add second and fifth elements of list to the end of the list and remove the penultimate element". I need to do this without using the module lists, just using recursion.
I have code which finds an element by index, which solves the problem of finding the second and fifth element (also not an ideal solution for me, because it's the same lists:nth function).
-module(task).
-export([remove_and_add/1]).
remove_and_add(List) ->
remove_penultimate(List) ++ [nth(2, List)] ++ [nth(5, List)].
nth(1, [H|_]) ->
H;
nth(N, [_|T]) ->
nth(N - 1, T).
But I don't understand how to remove the penultimate element without a length (how to implement remove_penultimate function).
Whenever you use ++, you can pretty much assume you are doing it inefficiently:
remove_penultimate(List) ++ [nth(2, List)] ++ [nth(5, List)].
If you can't use the lists module, then the first function every beginner needs to write is a reverse(List) function. Beside being one of the most useful functions, that will teach you the trick of how to add an "accumulator" variable to a function's parameter variables to store whatever data you want in it. Here is an example:
go(List) ->
go(List, []).
go([H|T], Acc) -> %% Acc starts off as a blank list, which can be used to store data
%% maybe do something here
go(T, [H|Acc]); %% storing data in the Acc list
go([], Acc) -> Acc.
You can add as many variables as you need to a function's parameters using the trick above, for instance:
go(List) ->
go(List, 1, none, none, []).
go([H|T], N, X, Y, Acc) -> ...
Examine this function:
show_previous(List) ->
show_previous(List, none).
show_previous([], Prev) -> %% A variable called Prev has been added to the function's parameters, and it starts off with the value none.
io:format("current: end of list, previous: ~w~n", [Prev]);
show_previous([Last], Prev) -> %% This clause only matches a list with one element.
io:format("current: ~w, penultimate: ~w~n", [Last, Prev]),
show_previous([H|T], Prev) ->
io:format("current: ~w, prev: ~w~n", [H, Prev]),
show_previous(T, H).
Note that in erlang, a function with the same name but with a different number of parameter variables (known as the "arity" of a function) is a completely different function, so show_previous/1 and show_previous/2 are completely different functions.
Here's another example of what you can do:
show([]) ->
io:format("!No more elements!~n");
show([X, Y]) -> %% only matches a list with two elements
io:format("penultimate: ~w, last: ~w~n", [X, Y]),
show([Y]);
show([H|T]) ->
io:format("current: ~w~n", [H]),
show(T). %% By whittling the list down one element at a time,
%% the list will eventually become a 2 element list
But I don't understand how to remove the penultimate element without a length.
You could always get the length by recursing over all the elements and counting them. It would be good practice to write your own length function. It's very simple. Remember though, it's more efficient to recurse over a list as few times as possible, and you should be able to solve your original problem by recursing over the list once, then reversing the list (which requires recursing over the list again).
Another possible approach to removing the penultimate element is to reverse the list, then ask yourself, "How do I remove the second element of a list?"
I came up with a solution that traverses the original list once, and when it comes to the end of the list, it reverses the Acc list and returns it. It takes this list:
[1, 2, 3, 4, 5, 6, 7]
and returns this list:
[1,3,4,7,2,5]
I would describe that operation as removing the penultimate element in the list and moving the 2nd and 5th elements to the end of the list. Copying the 2nd and 5th elements and adding the copies to the end of the list would be solved in a similar fashion.
Can anyone tell me what this means? I am new to this and my friend recommended me to post in this website.
By the way I'm new to Erlang.
If possible I want to write a code in editor and I don't even understand the question any sample input/output and how it works an explanation will do. Thankyou
It seems to me that the question refers to the implementation of lists:map/2, a function that applies the same function (received as a parameter) to all elements of a list and returns the resulting list.
In other words, this function.
You can check the OTP Github repo to see how that function is implemented:
map(F, List) when is_function(F, 1) ->
case List of
[Hd | Tail] -> [F(Hd) | map_1(F, Tail)];
[] -> []
end.
map_1(F, [Hd | Tail]) ->
[F(Hd) | map_1(F, Tail)];
map_1(_F, []) ->
[].
Or you can conceive an even simpler implementation, as…
map(F, []) -> [];
map(F, [H|T]) -> [F(H) | map(F, T)].
Both of them (for the OTP version, I'm referring to map_1/2) use pattern-matching in function clause heads to distinguish between the base case and the recursive step of the function.
The request that you received is to implement the same algorithm using a single function clause with a case clause instead of the two function clauses you see above.
Here's a simple example showing how to use function clauses, then case statements to do the same thing. Put the following code in a file named a.erl in some directory:
-module(a).
-export([show_stuff/1, show_it/1]).
show_stuff(1) ->
io:format("The argument was 1~n");
show_stuff(2) ->
io:format("The argument was 2~n");
show_stuff(_)->
io:format("The argument was something other than 1 or 2~n").
show_it(X) ->
case X of
1 -> io:format("The argument was 1~n");
2 -> io:format("The argument was 2~n");
_ -> io:format("The argument was something other than 1 or 2~n")
end.
Note that the file name, a.erl and the module directive:
-module(a).
must match. So, if you named your file homework1.erl, then the module directive in the file must be:
-module(homework1).
To save a lot of typing, it's best to use very short module names (as you will see below).
In a terminal window, switch directories to the directory containing a.erl:
~$ cd erlang_programs/
then launch the erlang shell:
~/erlang_programs$ erl
Erlang/OTP 24 [erts-12.0.2] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1]
Eshell V12.0.2 (abort with ^G)
Next, execute the following statements:
1> c(a). <--- Compiles the code in your file
{ok,a} <--- Or, you may get errors which must be corrected, then try recompiling.
2> a:show_stuff(1).
The argument was 1
ok
3> a:show_stuff(4).
The argument was something other than 1 or 2
ok
4> a:show_it(1).
The argument was 1
ok
5> a:show_it(4).
The argument was something other than 1 or 2
ok
6>
Note the syntax for calling a function defined in a file/module:
module_name:function_name(arg1, arg2, ... argn).
any sample input/output and how it works an explanation will do
In the documentaion linked in Brujo Benavides's answer, you can see:
Takes a function from As to Bs, and a list of As and produces a list of Bs by applying the function to every element in the list. This function is used to obtain the return values.
So F is a function (of a single argument) such as fun(X) -> X*2 end. See https://www.erlang.org/doc/programming_examples/funs.html#syntax-of-funs or https://www.erlang.org/doc/reference_manual/expressions.html#funs to understand fun expressions. List1 is a list of values which the function F can work on (in this case numbers) such as [1,2,3]. Then list:map(fun(X) -> X*2 end, [1,2,3]) calls fun(X) -> X*2 end on each element of list [1,2,3] and returns the list of return values [2,4,6]. Your function should give the same result on these arguments.
I'm trying to do a process on items in a sorted set in erlang, I call ZRANGE KEY 0 -1 WITHSCORES with eredis, the problem is it returns something like [<<"item1">>, <<"100">>, <<"item2">>, <<"200">>]. How can I run a function f on these items efficiently so that these calls occur: f(<<"item1">>, <<"100">>), f(<<"item2">>, <<"200">>)?
I solved it with something like this
f([X,Y|T]) -> [do_the_job(X,Y)|f(T)];
f([]) -> [].
then calling:
f(List).
Is there a more efficient way for doing so?
An optimized way is using tail-recursion. You can pass your list into do/1 function and it generates an empty list for storing the result of applying f/2 function on each two head items of the given list and then return the results:
do(List) ->
do(List, []).
do([X,Y | Tail], Acc) ->
do(Tail, [f(X, Y) | Acc]);
do([], Acc) ->
lists:reverse(Acc).
f(X, Y) ->
{X, Y}.
A note from Erlang documentation about tail-recursive efficiency:
In most cases, a recursive function uses more words on the stack for each recursion than the number of words a tail-recursive would allocate on the heap. As more memory is used, the garbage collector is invoked more frequently, and it has more work traversing the stack.
I was reading Learn You Some Erlang and I came upon this example in the Recursion chapter.
tail_sublist(_, 0, SubList) -> SubList;
tail_sublist([], _, SubList) -> SubList;
tail_sublist([H|T], N, SubList) when N > 0 ->
tail_sublist(T, N-1, [H|SubList]).
As the author goes on to explain that there is a fatal flaw in our code. It being that the sub lists hence produced would be reverse and we would have to re-reverse them to get the correct output. In contrast, what I did was use the ++ operator to avoid reversing the list later.
sublist_tail([],_,Acc) -> Acc;
sublist_tail(_,0,Acc) -> Acc;
sublist_tail([H|T],N,Acc) -> sublist_tail(T,N-1,Acc++[H]).
My question is, is the ++ operator more expensive than the | operator? And if it is, would my solution (using ++ operator) still be slow compared to the author's solution (including reversing the list to get the correct output)?
You might want to read about this issue in the Erlang efficiency guide, since there it says that building the list via | and then reversing the result is more efficient than using the appending ++ operator. If you want to know the performance difference, use timer:tc:
1> timer:tc(fun() -> lists:reverse(lists:foldl(fun(V, Acc) -> [V|Acc] end, [], lists:seq(1,1000))) end).
{1627,
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,
23,24,25,26,27|...]}
2> timer:tc(fun() -> lists:foldl(fun(V, Acc) -> Acc++[V] end, [], lists:seq(1,1000)) end).
{6216,
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,
23,24,25,26,27|...]}
Both approaches create lists of 1000 integers, but these measurements based on Erlang/OTP 17.5 show the prepending/reversing version is roughly 4x faster than the appending version (YMMV of course).
is the ++ operator more expensive than the | operator?
That depends. If you use it correctly, then no. ++ is only dangerous when you have a big left-hand-side operand.
Each time a "++"-operator is invoked on a left-hand List (like: List1 ++ List2), you are creating a new List, that is a copy of your left-hand operand (List1). Each copy operation then has a runtime, that is dependent on the length of your List1 (which keeps growing with your iterations).
So, if you prepend your values 'head first', you don't have to perform a copy-operation over the whole list in each step. This also means, accumulation with ++ at the head of the List wouldn't be so bad either, since only the "H"-value is copied once in each iteration:
sublist_tail([H|T],N,Acc) -> sublist_tail(T,N-1,[H]++Acc).
But if you are already accumulating head-first (and thus have to reverse later anyhow), you can do it with the cons-operator (|)
sublist_tail([H|T],N,Acc) -> sublist_tail(T,N-1,[H|Acc]).
This is the 'proper' way, since (please correct me if I am wrong) ++ is only syntactic sugar and is implemented internally with a cons-operator (|).
I'm trying to parse a binary file and when it comes to returning numbers packed in little endian into 16 bits, I am hoping that this would work:
foo(Bin, Bits) when is_binary(Bin) ->
<<A, B, C, D, _Rest>> = Bin,
(bar(<<A, B>>, Bits) =/= 0) and (bar(<<C, D>>, Bits) =/= 0).
bar(<<N:16/little-unsigned-integer>>, Bits) ->
binary:at(Bits, N).
Unfortunately, the matcher doesn't work when Bin is 4 bytes or less. Is there a better way to make it so the rest can be empty? If I could avoid testing binary length in the caller, the better.
You could do something like:
foo(<<A:16/little-unsigned-integer,B:16/little-unsigned-integer,_Rest/binary>>, Bits) ->
(binary:at(Bits, A) =/= 0) and (binary:at(Bits, B) =/= 0).
This will not work with a binary which is less than 4 bytes long. What is supposed to happen in that case?
N.B. binary:at/2 works on binaries not bitstrings and the offset is in bytes.