I'm new to erlang. I wonder how to write a function which returns the first N elements in a list?
I've tried:
take([],_) -> [];
take([H|T],N) when N > 0 -> take([H,hd(L)|tl(T)], N-1);
take([H|T],N) when N == 0 -> ... (I'm stuck here...)
Any hint? thx
Update: I know there's a function called "sublist" but I need to figure out how to write that function by my own.
I finally figured out the answer:
-module(list).
-export([take/2]).
take(List,N) -> take(List,N,[]).
take([],_,[]) -> [];
take([],_,List) -> List;
take([H|T], N, List) when N > 0 -> take(T, N-1, lists:append(List,[H]));
take([H|T], N, List) when N == 0 -> List.
A simple solution is:
take([H|T], N) when N > 0 ->
[H|take(T, N-1)];
take(_, 0) -> [].
This will generate an error if there are not enough elements in the list.
When you use an accumulator as you are doing you do not usually append elements to the end of it as this is very inefficient (you copy the whole list each time). You would normally push elements on to it with [H|List]
. It will then be in the reverse order but you then do a lists:reverse(List)
to return them in the right order.
take(List, N) -> take(List, N, []).
take([H|T], N, Acc) when N > 0 ->
take(T, N-1, [H|Acc]);
take(_, 0, Acc) -> lists:reverse(Acc).
The accumulator version is tail recursive which is a Good Thing but you need to do an extra reverse which removes some of the benefits. The first version I think is clearer. There is no clear case for either.
In Erlang, take
is spelled lists:sublist
:
L = [1, 2, 3, 4];
lists:sublist(L, 3). % -> [1, 2, 3]