James
James

Reputation: 771

Counting down from N to 1

I'm trying to create a list and print it out, counting down from N to 1. This is my attempt:

%% Create a list counting down from N to 1 %%
-module(list).
-export([create_list/1]).

create_list(N) when length(N)<hd(N) ->
 lists:append([N],lists:last([N])-1),
 create_list(lists:last([N])-1); 
create_list(N) ->
 N.

This works when N is 1, but otherwise I get this error:

172> list:create_list([2]).
** exception error: an error occurred when evaluating an arithmetic expression
     in function  list:create_list/1 (list.erl, line 6)

Any help would be appreciated.

Upvotes: 0

Views: 219

Answers (3)

rvirding
rvirding

Reputation: 20916

You should generally avoid using append or ++, which is the same thing, when building lists. They both add elements to the end of a list which entails making a copy of the list every time. Sometimes it is practical but it is always faster to work at the front of the list.

It is a bit unclear in which order you wanted the list so here are two alternatives:

create_up(N) when N>=1 -> create_up(1, N).     %Create the list 

create_up(N, N) -> [N];
create_up(I, N) ->
    [I|create_up(I+1, N)].

create_down(N) when N>1 ->                     %Add guard test for safety
    [N|create_down(N-1)];
create_down(1) -> [1].

Neither of these are tail-recursive. While tail-recursion is nice it doesn't always give as much as you would think, especially when you need to call a reverse to get the list in the right order. See Erlang myths for more information.

Upvotes: 4

stemm
stemm

Reputation: 6050

If I correctly understand your question, here is what you'll need

create_list(N) when N > 0 ->
        create_list(N, []).

create_list(1, Acc) ->
        lists:reverse([1 | Acc]);
create_list(N, Acc) ->
        create_list(N - 1, [N | Acc]).

If you work with lists, I'd suggest you to use tail recursion and lists construction syntax.

Also, to simplify your code - try to use pattern matching in function declarations, instead of case expressions

P.S. The other, perhaps, most simple solution is:

create_list(N) when N > 0 ->
        lists:reverse(lists:seq(1,N)).

Upvotes: 3

halfelf
halfelf

Reputation: 10107

The error is lists:last([N])-1. Since N is an array as your input, lists:last([N]) will return N itself. Not a number you expect. And if you see the warning when compiling your code, there is another bug: lists:append will not append the element into N itself, but in the return value. In functional programming, the value of a variable cannot be changed.

Here's my implementation:

create_list(N) ->
    create_list_iter(N, []).

create_list_iter(N, Acc) ->
    case N > 0 of
        true -> NewAcc = lists:append(Acc, [N]),
                create_list_iter(N-1, NewAcc);
        false -> Acc
    end.

Upvotes: 3

Related Questions