Erlang List & List Module

Erlang Control Flow Statement

List is the the most important data type in Erlang, as in every functional programming language. In this article, I will present the Erlang’s lists module and its most important functions.

Syntax

1
[Element1, Element2, ..., ElementN]

N is called the length of the list. So, [] is the empty list.

Decomposing & Pattern Matching

An empty list pattern matches with [].

1
2
3
4
5
6
7
8
9
10
11
12
1> Empty = [].
[]
2> Empty == [].
true
3> Empty = [].
[]
4> NotEmpty = [1].
[1]
5> Empty == NotEmpty.
false
6> Empty = NotEmpty.
** exception error: no match of right hand side value [1]

A non-empty list pattern matches with [Head | Tail].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
1> [Head | Tail] = [1, 2, 3, 4].
[1,2,3,4]
2> Head.
1
3> Tail.
[2,3,4]
4> [Head1 | Tail1] = Tail.
[2,3,4]
5> Head1.
2
6> Tail1.
[3,4]
7> [Head2 | Tail2] = [].
** exception error: no match of right hand side value []

Normal Representation
The format [Element1, Element2, …, ElementN] is a shorthand of [Element1 | [Element2 | … | [ElementN | []] … ] representation.
Example: the list [1, 2, 3] is a shorthand of [1 | [2 | 3 | []]], that is the normal representation of a list.

Decomposing:

1
2
3
4
5
6
7
8
9
10
1> [A | [B |[C | D]]] = [1, 2, 3].
[1,2,3]
2> A.
1
3> B.
2
4> C.
3
5> D.
[]

Composing:

1
2
3
4
5
6
7
8
1> List = [2,3].
[2,3]
2> List1 = [1 | List].
[1,2,3]
3> List2 = [-1 | [0 | List1]].
[-1,0,1,2,3]
4> List3 = [[-3, -2] | List2].
[[-3,-2],-1,0,1,2,3] % the head is just 1 element

Of course, since it is more readable and easier to write, the shorthand representation is usually used:

1
2
3
4
5
6
7
8
9
10
11
1> [A, B, C] = [1, 2, 3].
[1,2,3]
2> [A, B, C, D] = [1, 2, 3]. % does not match cause
% the left-hand side matches a 4-elements list
** exception error: no match of right hand side value [1,2,3]
3> [A, B, C | D] = [1, 2, 3].
[1,2,3]
4> D.
[]
5> [-3, -2 | [-1, 0 | [1 | [2,3]]]].
[-3,-2,-1,0,1,2,3]

List Parsing
The pattern matching you saw before can be used in a function in order to parse the list:

1
2
3
4
parse([]) ->
  parsed.
parse([Head | Tail]) ->
  parse(Tail).

Concatenation
Two lists can be concatenated using ++:

1
2
3
4
5
6
7
8
9
10
1> L1 = [1, 2], L2 = [3, 4, 5].
[3,4,5]
2> L1 ++ L2.
[1,2,3,4,5]
3> L1 ++ L2 ++ L1.
[1,2,3,4,5,1,2]
4> Mirror = fun(List) -> List ++ lists:reverse(List) end.
#Fun<erl_eval .6.13229925>
5> Mirror([a, b, {c}]).
[a,b,{c},{c},b,a]

Difference
You can take the difference of two lists (the left-hand side one without the element of the right-hand side) using the – operator:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1> [1, 2, 3] -- [1, 2, 3].
[]
2> [1, 2, 3] -- [1, 3].
[2]
3> [1, 2, 3] -- [1, 3, 3].
[2]
4> [1, 3, 2, 3] -- [1, 3, 3].
[2]
5> [3, 1, 3, 2, 3] -- [1, 3, 3].
[2,3]
6> [1, 2, 3] -- [a, b].
[1,2,3]
7> Delete = fun(List, Element) -> List -- [Element] end.
#Fun<erl_eval .12.113037538>
8> Delete([1,2,3,4,1], 1).
[2,3,4,1]

Module Lists

The lists module defines some commonly used list processing functions. This module is extremely useful, so it is a good idea to “remember” what functions it provides.

all/2
Called as all(Pred, List). Returns true if Pred(Element) returns true for all lists’ elements.

1
2
3
4
5
6
7
8
9
10
1> L = [2, 4, 6, 8],
1> F = fun(X) -> X rem 2 == 0 end,
1> lists:all(F, L).
true
2> f().
ok
3> L = [2, 4, 5, 8],
3> F = fun(X) -> X rem 2 == 0 end,
3> lists:all(F, L).
false

append/1|2
Concatenates the lists to one.

1
2
3
4
1> lists:append([[1, 2], [3], [4, 5]]).
[1,2,3,4,5]
2> lists:append([1, 2], [3, 4]).
[1,2,3,4]

Notice that the operator ++ and the function append/2 are the same.

delete/2
Deletes an element from the list (first occurrence, if any).

1
2
1> lists:delete(a, [d, a, d, a, d]).
[d,d,a,d]

concat/1
Accepts a list of items (atom, integer, float, string) and returns the concatenation of their textual representation as a list.

1
2
1> lists:concat(["ab", '.', 1]).
"ab.1"

filter/2
Called as filter(Pred, List). Returns a list containing only the elements that return true for the Pred.

1
2
3
4
5
6
1> Gt10 = fun(X) -> X > 10 end, lists:filter(Gt10, [1, 2, 22, 3, 44, 5, 66]).
[22,44,66]
2> L = [1, a, b, 2, c, 3.0, d, {4}].
[1,a,b,2,c,3.0,d,{4}]
3> lists:filter(fun(X) -> is_number(X) end, L).
[1,2,3.0]

flatten/1
Returns a flattened (no element is a list) version of the input list.

1
2
1> lists:flatten([1, [2], [3, 4, [5, [6, 7]]], [[[[8]]]]]).
[1,2,3,4,5,6,7,8]

key*** functions
There are several functions which their name starts with the word “key”. They are all used to process lists of tuples.

1
2
3
4
5
6
7
8
9
10
1> Kl = [{a, k1, a}, {b, k2, b}, {c, k3, c}, {e, k5, e}].
[{a,k1,a},{b,k2,b},{c,k3,c},{e,k5,e}]
2> lists:keydelete(k3, 2, Kl).
[{a,k1,a},{b,k2,b},{e,k5,e}]
3> lists:keysearch(k3, 2, Kl).
{value,{c,k3,c}}
4> lists:keysearch(k4, 2, Kl).
false
5> lists:keyreplace(k3, 2, Kl, {new, tuple}).
[{a,k1,a},{b,k2,b},{new,tuple},{e,k5,e}]

last/1
Returns the last element of the list.

1
2
1> lists:last([1, 2, 3]).
3

map/2
Called as map(Fun, List). Applies function Fun to every item of the list and returns the resulting list.

1
2
1> lists:map(fun(I) -> 2 * I end, [1, 2, 3]).
[2,4,6]

partition/2
Partitions a list to two according to if the elements satisfy or not a given predicate.

1
2
1> lists:map(fun(I) -> 2 * I end, [1, 2, 3]).
[2,4,6]

reverse/1|2
Returns the reverse of a list.

1
2
3
4
1> lists:reverse([a, b, c, d]).
[d,c,b,a]
2> lists:reverse([a, b, c, d], [1, 2, 3]).
[d,c,b,a,1,2,3]

sort/1|2
Sorts a list to increasing order or according to a given function.

1
2
3
4
5
6
7
8
1> L = [3, 1, 2, 5, 4].
[3,1,2,5,4]
2> lists:sort(L).
[1,2,3,4,5]
3> Gt = fun(I, J) -> I > J end.
#Fun<erl_eval .12.113037538>
4> lists:sort(Gt, L).
[5,4,3,2,1]

sum/1
Returns the sum of the elements of a list containing numbers.

1
2
1> lists:sum([1, 2.2, 3]).
6.2

u*** functions
There are several function which their name starts with “u” and the results they return contain no duplicates.

1
2
1> lists:usort([5, 3, 2, 3, 2, 1, 4, 5]).
[1,2,3,4,5]