# ✓ Functional Sequences Transformations¶

## Sequeces in Clojure¶

Sequences are everywhere in Clojure. It’s a powerful abstract over many different data structures and programming scenarios.

### A few functions to process sequences¶

```
(let [my-list '(:a :b :c)]
(first my-list))
```

```
:a
```

```
(let [my-list '(:a :b :c)]
(last my-list))
```

```
:c
```

```
(let [my-vec [1 2 3]]
(first my-vec))
```

```
1
```

```
(let [my-vec [1 2 3]]
(last my-vec))
```

```
3
```

```
(let [my-vec [1 2 3]]
(take 2 my-vec))
```

```
(1 2)
```

### Hash-maps are sequences too¶

Hash-maps can also be used as a sequence. It’s a sequence of `[key value]`

pairs.
So, each element is a vector of length two consisting of the key and the value.

```
(let [my-hashmap {:a 1
:b 2
:c 3}]
(first my-hashmap))
```

```
[:a 1]
```

```
(let [my-hashmap {:a 1
:b 2
:c 3}]
(last my-hashmap))
```

```
[:c 3]
```

```
(let [my-hashmap {:a 1
:b 2
:c 3}]
(take 2 my-hashmap))
```

```
([:a 1] [:b 2])
```

## Review of for-iteration¶

The `for`

-form always evaluates to a sequence. The for-form generates the elements
by iterating over one or more *input* sequences.

### General form¶

```
(for [ <symbol> <sequence>
<symbol> <sequence>
...
:when <condition>
:while <condition>
:let [binding...]]
<expression>)
```

```
(for [x [:a :b :c]
y [1 2 3]]
[x y])
```

```
([:a 1] [:a 2] [:a 3] [:b 1] [:b 2] [:b 3] [:c 1] [:c 2] [:c 3])
```

### Why use for-form?¶

The for-form is similar to the more traditional for-loops in Python, and thus are easier to read for most people.

### Why not use the for-form?¶

For-form is not friendly to **composition**.

Consider the scenario of:

The first for-form generates a sequence.

Then a second for-form process the elements from the first for-form

```
(defn format-elements [x y]
(str "x=" x " and y=" y))
```

```
#'user/format-elements
```

```
(for [elem (for [x [:a :b :c]
y [1 2]]
[x y])]
(apply format-elements elem))
```

```
("x=:a and y=1" "x=:a and y=2" "x=:b and y=1" "x=:b and y=2" "x=:c and y=1" "x=:c and y=2")
```

```
(for [string (for [elem (for [x [:a :b :c]
y [1 2]]
[x y])]
(apply format-elements elem))]
(clojure.string/upper-case string))
```

```
("X=:A AND Y=1" "X=:A AND Y=2" "X=:B AND Y=1" "X=:B AND Y=2" "X=:C AND Y=1" "X=:C AND Y=2")
```

### Functional programming¶

Functions are composable.

Using higher order functions, we have interesting ways to **describe** sequence transformations.

## Map¶

### About map¶

`map`

is not a**form**. It’s is a**function**.The signature of the

`map`

function is:

Note

See: https://clojuredocs.org/clojure.core/map

```
(map <function> <sequence>)
(map <function> <sequence-1> <sequence-2>)
(map <function> <sequence-1> <sequence-2> <sequence-3>)
```

The function is called the

**mapping function**, or sometimes the**mapper**.The map function returns a (lazy) sequence.

### Map action¶

The elements from input sequences are used as input arguments to the mapping function. Elements from the input sequences are matched up until one of the sequence is exhausted.

The return values of the mapping function form the output sequence.

### Adding numbers pairwise¶

```
(let [xs [1 2 3]
ys [4 5 6 7 8]]
(map + xs ys))
```

```
(5 7 9)
```

```
(let [xs [1 2 3]
ys [4 5 6]]
(map vector xs ys))
```

```
([1 4] [2 5] [3 6])
```

### Revisiting iterations¶

Note: `map`

is not equivalent to `for`

-form when applied to multiple sequences.

```
(for [x [:a :b :c]
y [1 2]]
[x y])
```

```
([:a 1] [:a 2] [:b 1] [:b 2] [:c 1] [:c 2])
```

```
(let [xs [:a :b :c]
ys [1 2]]
(map vector xs ys))
```

```
([:a 1] [:b 2])
```

### Map is composable¶

```
(map format-elements [:a :b :c] [1 2])
```

```
("x=:a and y=1" "x=:b and y=2")
```

```
(map clojure.string/upper-case
(map format-elements [:a :b :c] [1 2]))
```

```
("X=:A AND Y=1" "X=:B AND Y=2")
```

### Map composition using threading¶

```
(->> (map format-elements [:a :b :c] [1 2])
(map clojure.string/upper-case))
```

```
("X=:A AND Y=1" "X=:B AND Y=2")
```

## Filter¶

### About filter¶

Note

```
(filter <predicate> <sequence>)
```

Recall a predicate is a function that returns

**true**or**false**.The filter function returns a sequence from the input sequence that evaluate to true by the predicate function.

### Example¶

```
(filter #(< 4 (count %))
["hello"
"world"
"again"
"and"
"again"])
```

```
("hello" "world" "again" "again")
```

### Filter is composable¶

```
(filter #(clojure.string/includes? % "a")
["hello"
"world"
"again"
"and"
"again"])
```

```
("again" "and" "again")
```

```
(filter #(< 4 (count %))
(filter #(clojure.string/includes? % "a")
["hello"
"world"
"again"
"and"
"again"]))
```

```
("again" "again")
```

### Threading and composition¶

```
(->> ["hello"
"world"
"again"
"and"
"again"]
(filter #(< 4 (count %)))
(filter #(clojure.string/includes? % "a")))
```

```
("again" "again")
```

## Reduce¶

Reduce is the most powerful form of functional sequence processing.

### About reduce¶

Note

```
(reduce <reducer-fn> <initial-value> <sequence>)
```

where the `reducer-fn`

has the signature of:

```
(<reducer-fn> <state-value> <input-element>)
```

Unlike *map* and *filter*, *reduce* can produce data value of **any** type.

It uses a function, known as the **reducer**, to iteratively transform a *state* value
with the elements in the input sequence.

### Reduce action¶

During the reduce iteration, we starts with a state value being the `initial-value`

.

For each `element`

in the sequence, a new state value is computed as:

```
(<reducer-fn> state-value element)
```

### Reducer explained¶

Suppose we have an input sequence:

```
["hello" "world" "again" "and" "again"]
```

We may want to compute the **total** characters.

Use an integer as the state value, with initial value set to 0.

Use a reducer function to compute the new state value for each input element.

The total characters can be computed using reduce.

```
(fn [total string] (+ total (count string)))
```

```
#function[user/eval5902/fn--5903]
```

```
(reduce (fn [total string] (+ total (count string)))
0
["hello" "world" "again" "and" "again"])
```

```
23
```

### Another example of reduce¶

Adding a sequence of numbers using reduce can be done using
`+`

as the reducer function.

```
(reduce + 0 (range 1000000))
```

```
499999500000
```

### Composability of map/filter/reduce¶

How many characters are there in total for strings that start with “a” in the sequence

```
["hello" "world" "again" "and" "again"]
```

```
(->> ["hello" "world" "again" "and" "again"]
(filter #(clojure.string/starts-with? % "a")))
```

```
("again" "and" "again")
```

```
(->> ["hello" "world" "again" "and" "again"]
(filter #(clojure.string/starts-with? % "a"))
(map count))
```

```
(5 3 5)
```

```
(->> ["hello" "world" "again" "and" "again"]
(filter #(clojure.string/starts-with? % "a"))
(map count)
(reduce + 0))
```

```
13
```

## Summary¶

Functional programming prompts abstraction by exploring patterns that involve higher order functions.

Map/filter/reduce functions allow very succint and composable code.

Clojure provides different programming constructs from low-level loop/recur to sequence iteration with for-forms, to the higher level abstraction using map/filter/reduce.