Processing items in a list

Lists provide a useful way of representing collections of data, such as the notes in a tune, or the sequence of analogue values read from an input. This section introduces two very useful functions for processing items in a list.

Processing the items in a list - mapc

The function mapc performs a function on each item in a list. For example:

> (mapc print '(0 1 2 3))

0 
1 
2 
3 nil

Here's a more interesting example. The following list represents the notes of a familiar tune:

(defvar tun '(0 0 7 7 9 9 7 nil 5 5 4 4 2 2 0))

We've used nil to insert a gap. The following function pla plays a single note, or a gap if its argument is nil:

(defun pla (x) (when x (note 3 x 4)) (delay 200) (note) (delay 200))

We can use mapc to apply the function to each of the items in the tune. The first argument is a function, and the second argument is the list we want to process:

(mapc pla tun)

Connect a piezo speaker between pin 3 and GND on an Arduino Uno to hear the tune.

Alternatively, on an Arduino Mega 2560 connect the piezo speaker between pin 9 and GND and change the definition of pla to:

(defun pla (x) (when x (note 9 x 4)) (delay 200) (note) (delay 200)) 

Transforming a list - mapcar

The related function mapcar applies a specified function to each of the items in a list, but it then returns the list of results. For example:

> (mapcar 1+ '(0 1 2 3 4))
(1 2 3 4 5)
We can create a function inv to invert a note x by changing it to (- 12 x):
(defun inv (x) (when x (- 12 x)))
Again, nil represents a gap which is left unchanged. We can use mapcar to invert the whole tune:
> (mapcar inv tun)
(12 12 5 5 3 3 5 nil 7 7 8 8 10 10 12)

or we can play the inverted tune with:

 (mapc pla (mapcar inv tun)

Both mapc and mapcar can alternatively take a function of two arguments, and two lists, and apply the function to corresponding elements of both lists until the shortest list runs out. For example:

> (mapcar * '(1 2 3) '(4 5 6))
(4 10 18)

You can alternatively specify the function using a lambda expression. For example, to square each item in a list:

> (mapcar (lambda (x) (* x x)) '(1 2 3 4 5))
(1 4 9 16 25)