Calling lists:append(List1, List2)
will result in that
the whole List1 has to be traversed. When recursively building a
list always attach the element to the begining of the list and
not to the end. In the case that the order of the elements in
the list is important you can always reverse the list when it
has been built! It is cheaper to reverse the list in the final
step, than to append the element to the end of the list in each
recursion. Note that ++ is equivalent to lists:append/2. As an
example consider the tail-recursive function fib that creates a
list of Fibonacci numbers. (The Fibonacci series is formed by
adding the latest two numbers to get the next one, starting from
0 and 1.)
> fib(4). [0, 1, 1, 2, 3]
DO
fib(N) -> fib(N, 0, 1, [0]). fib(0, Current, Next, Fibs) -> lists:reverse(Fibs); % Reverse the list as the order is important fib(N, Current, Next, Fibs) -> fib(N - 1, Next, Current + Next, [Next | Fibs]).
DO NOT
fib(N) -> fib(N, 0, 1, [0]). fib(0, Current, Next, Fibs) -> Fibs; fib(N, Current, Next, Fibs) -> fib(N - 1, Next, Current + Next, Fibs ++ [Next]).
When using the function delete in the lists module there is no reason to check that the element is actually part of the list. If the element is not part of the list the delete operation will be considered successful.
DO
... NewList = lists:delete(Element, List), ...
DO NOT
... NewList = case lists:member(Element, List) of true -> lists:delete(Element, List); false -> List end, ...
Use functions like lists:foldl/3 and lists:mapfoldl/3 to avoid traversing lists more times than necessary. The function mapfold combines the operations of map and foldl into one pass. For example, we could sum the elements in a list and double them at the same time:
> lists:mapfoldl(fun(X, Sum) -> {2*X, X+Sum} end, 0, [1,2,3,4,5]). {[2,4,6,8,10],15}
Also consider the function evenMultipleSum below where we make one list traversal in the first version and three in the second version. (This may not be a very useful function, but it serves as a simple example of the principle.)
DO
evenMultipleSum(List, Multiple) -> lists:foldl(fun(X, Sum) when (X rem 2) == 0 -> X * Multiple + Sum; (X, Sum) -> Sum end, 0, List).
DO NOT
evenMultipleSum(List, Multiple) -> FilteredList = lists:filter(fun(X) -> (X rem 2) == 0 end, List), MultipleList = lists:map(fun(X) -> X * Multiple end, FilteredList), lists:sum(MultipleList).
lists:flatten/1
is a very general function and because
of this it can be quite expensive to use. So do not use it if
you do not have to. There are especially two senarios where you
do not need to use flatten
append/1
Port example
DO
... port_command(Port, DeepList) ...
DO NOT
... port_command(Port, lists:flatten(DeepList)) ...
A common way that people construct a flat list in vain is when they use append to send a 0-terminated string to a port. In the example below please note that "foo" is equivalent to [102, 111, 111].
DO
... TerminatedStr = [String, 0], % String="foo" => [[102, 111, 111], 0] port_command(Port, TerminatedStr) ...
DO NOT
... TerminatedStr = String ++ [0], % String="foo" => [102, 111, 111, 0] port_command(Port, TerminatedStr) ...
Append example
DO
> lists:append([[1], [2], [3]]). [1,2,3] >
DO NOT
> lists:flatten([[1], [2], [3]]). [1,2,3] >
![]() |
If your deep list is a list of strings you will not get the wanted result using flatten. Remember that strings are lists. See example below: |
> lists:append([["foo"], ["bar"]]). ["foo","bar"] > lists:flatten([["foo"], ["bar"]]). "foobar"