Reputation: 125
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?
Upvotes: 0
Views: 203
Reputation: 1958
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.
list
module, you can't use it in guards. Only BIFs are allowed there.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.
Upvotes: 1
Reputation: 48599
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]]
Upvotes: 1