In one of the last posts, we discussed functions to add or remove items from lists with `push`

, `pop`

and so on. Today, we will see how to apply functions to lists with **mapping functions**.

### What is mapping?

In mathematics, the term **mapping** is often used as a synonym for function. It means that a set `X`

is assigned to elements of a set `Y`

. `X`

is also called "domain" and `Y`

"codomain".

Now in programming, a "set" is usually a collection of data (in PicoLisp often in form of a list). These sets are transformed via **functions**. In order to do this in a generic way, many functional programming languages provide *higher-order* functions that take the function to be mapped as one of its **argument**.

### Input and Output values

Obviously, there are several ways to implement this specifically:

**Input handling**:

- We can apply a function to the list
**as a whole**(I call this "one-to-X" function in this post), - or to
**each single element**("many-to-X" function).

**Function output**:

- Do we get a
**new list**as return value ("X-to-many"), - or a
**single element**("X-to-one")?

The table below shows an overview over some important higher-order functions based on their input/output classification.

We will go through all four categories in detail now, to understand what each of these functions does and what the subtle differences are.

## Many-to-Many functions

Let's start with the many-to-many functions, as these are probably the most intuitive ones.

`mapcar`

The typical example is `mapcar`

: It applies a function to each element of a list. If additional arguments are given, their elements are passed to the function too.

```
: (mapcar + (1 2 3) (4 5 6))
-> (5 7 9)
: (mapcar + (1 2 3) 5)
-> (6 7 8)
: (mapcar '((X Y) (+ X (* Y Y))) (1 2 3 4) (5 6 7 8))
-> (26 38 52 68)
```

`filter`

and `extract`

The second example is `filter`

, which applies a function to each element of a list, and returns all **elements** where the function returns non-`NIL`

.

```
: (filter num? (1 A 2 (B) 3 CDE))
-> (1 2 3)
: (filter < (2 9 3 8 4 7) (5 4 3 9 9 5))
-> (2 8 4)
```

Its counterpart is `extract`

, which returns all non-`NIL`

**values** of the function. Note the difference to `filter`

in the example below:

```
: (setq A NIL B 1 C NIL D 2 E NIL F 3)
-> 3
: (filter val '(A B C D E F))
-> (B D F)
: (extract val '(A B C D E F))
-> (1 2 3)
```

`mapcan`

`mapcan`

applies the function to each element just like `mapcar`

, but it returns a **concatenated** list of results. Observe the difference between `mapcar`

and `mapcan`

in the example below:

```
: (mapcan reverse '((a b c)( d e f)(g h i)))
-> (c b a f e d i h g)
: (mapcar reverse '((a b c)( d e f)(g h i)))
-> ((c b a) (f e d) (i h g))
```

`by`

`by`

takes two functions as argument, where the second one is typically either `sort`

or `group`

. It returns a sorted or grouped list of elements. Let's take the following data set "A=1, B=2, C=3":

```
: (setq A 1 B 2 C 3)
-> 3
# sort "C A B" by their value:
: (by val sort '(C A B))
-> (A B C)
```

In the second common use case of `by`

, we call it together with `group`

. `group`

builds a list of lists by grouping all elements with the same CAR. Let's say we want to group a list of numbers by even and uneven values:

```
: (setq L (3 11 6 2 9 5 4 10 12 7 8 1))
-> (3 11 6 2 9 5 4 10 12 7 8 1)
# group by even or uneven number:
: (by '((N) (bit? 1 N)) group L)
-> ((3 11 9 5 7 1) (6 2 4 10 12 8))
```

## Many-to-One functions

Now we come to the "Many-To-One functions" that apply a function to **each element** of a list, but return a **single value** instead of a list.

`mapc`

`mapc`

is very similar to `mapcar`

, but it returns only the last calculation instead of all values. View `mapcar`

and `mapc`

in comparison:

```
: (mapcar '((X Y) (+ X (* Y Y))) (1 2 3 4) (5 6 7 8))
-> (26 38 52 68)
: (mapc '((X Y) (+ X (* Y Y))) (1 2 3 4) (5 6 7 8))
-> 68
```

`apply`

Another example is `apply`

:

```
: (apply + (1 2 3))
-> 6
: (apply * (5 6) 3 4)
-> 360
: (apply '((X Y Z) (* X (+ Y Z))) (3 4 5))
-> 27
```

*Note: One could argue that apply doesn't apply a function *to each element

*, but rather passes the list as arguments to a function. In this case it is rather a "one-to-one" mapping. I leave it up to you how you judge it.*

`find`

and `pick`

Similarly to `filter`

/`extract`

, we can return a *single* element from a dataset based on certain criteria with `find`

. It returns the first element that fulfills the requirement and then stops the execution.

```
: (find '((A B) (> A B)) (1 2 3 4 5 6) (6 5 4 3 2 1))
-> 4
: (find > (1 2 3 4 5 6) (6 5 4 3 2 1)) # shorter
-> 4
```

`pick`

works similarly to `extract`

, as it returns the *value* of the function that fulfills the requirement. `find`

and `pick`

in comparison:

```
: (setq A NIL B 1 C NIL D 2 E NIL F 3)
-> 3
: (find val '(A B C D E))
-> B
: (pick val '(A B C D E))
-> 1
```

`fully`

, `cnt`

, `maxi`

, `mini`

, `sum`

More similar functions (you can tell the function from the name, I guess): `fully`

, `cnt`

, `maxi`

, `mini`

, `sum`

. Below you can find some examples:

```
: (fully gt0 (1 2 3))
-> T
: (fully gt0 (1 -2 3))
-> NIL
: (cnt cdr '((1 . T) (2) (3 4) (5)))
-> 2
: (setq A 1 B 2 C 3)
-> 3
: (maxi val '(A B C))
->C
: (mini val '(A B C))
-> A
: (sum val '(A B C))
-> 6
```

## One-to-Many functions

Up to now, all functions have always been applied to **each element** of the provided list. Now we will discuss two functions that instead apply the function to the list *as a whole* and return a new list as result.

`mapcon`

`mapcon`

applies a function to a list, and to **all successive CDRs**. Then all results are concatenated.

```
: (mapcon copy '(1 2 3 4 5))
-> (1 2 3 4 5 2 3 4 5 3 4 5 4 5 5)
```

First the whole list `(1 2 3 4 5)`

is copied, after that its CDR `(2 3 4 5)`

and so on. Observe the difference between `mapcon`

and `mapcan`

:

```
: (mapcan reverse '((a b c)( d e f)(g h i)))
-> (c b a f e d i h g)
: (mapcon reverse '((a b c)( d e f)(g h i)))
-> ((g h i) (d e f) (a b c) (g h i) (d e f) (g h i))
```

`mapcan`

reverses each single list item, while `mapcon`

reverses the list *as a whole*, and after that each CDR successively. Both functions concatenate the result to a new list.

`maplist`

Similarily, `maplist`

also applies a function to a list as well as to all successive CDRs, but without concatenating the result:

```
: (maplist cons (1 2 3) '(A B C))
-> (((1 2 3) A B C) ((2 3) B C) ((3) C))
: (maplist reverse '((a b c)(d e f) (g h i)))
-> (((g h i) (d e f) (a b c)) ((g h i) (d e f)) ((g h i)))
```

`seek`

Another interesting example is `seek`

, which applies a function to a list and its CDR until non-`NIL`

is returned:

```
: (seek '((X) (> (car X) 9)) (1 5 8 12 19 22))
-> (12 19 22)
```

## One-to-One functions: `map`

Finally, we have the plain `map`

function. Like `maplist`

and `mapcon`

, it applies the function to list and all the successive CDRs, but returns only the result of the *last application*.

```
: (map println (1 2 3 4) '(A B C))
(1 2 3 4) (A B C)
(2 3 4) (B C)
(3 4) (C)
(4) NIL
-> NIL
```

## Some thoughts about the `map`

function group

As you might have noticed, there are six functions with very similar names: `map`

, `mapc`

, `maplist`

, `mapcar`

, `mapcon`

, `mapcan`

. Instead of the relations above, a better way to classify them might be by argument and return value:

```
Argument Return
List CAR Value
------------+----------+---------
map mapc | last
maplist mapcar | list
mapcon mapcan | conc
```

While `map`

, `maplist`

and `mapcon`

take the whole list as argument, `mapc`

, `mapcar`

and `mapcan`

iterate through the list and use each CAR. The return value is either the last element, a list or a concatenated list.

All the functions above can be emulated through these functions, and in fact, all `map-`

functions can be replaced by `mapcon`

only.

Examples: Emulate `mapcar`

by `mapcon`

:

```
(mapcar inc (1 2 3))
(mapcon '((L) (list (inc (car L)))) (1 2 3))
```

Emulate `maplist`

by `mapcon`

:

```
(maplist '((L) (+ (car L) (cadr L))) (1 2 3))
(mapcon '(((A B)) (list (+ A B))) (1 2 3))
```

Emulate `filter`

by `mapcan`

:

```
(filter foo Lst)
(mapcan '((X) (and (foo X) (list X))) Lst)
```

### Wrap-up

While some of these functions have really specific uses cases (like `by`

), other functions are widely used like `mapcar`

, `filter`

and so on. I hope this post helped to sort the different types of mapping functions.

We will see some interesting use cases of `by`

and `mapcon`

in the next Euler riddle.