# List Comprehensionλ︎

In general terms, list comprehensions should:

• be distinct from (nested) for loops and the use of map & filter functions within the syntax of the language.
• return either a list or an iterator (an iterating being something that returns successive members of a collection, in order),

In Clojure, list comprehension is via the `for` function. This is different to the for in other languages as you will see.

``````(for [number [1 2 3]] (* number 2))
``````

The `for` function should be read as follows:

"for each number in the collection [1 2 3], apply the function (* number 2)"

Couldn't we just do this with map? Yes, we could.

``````(map #(* % 2) [1 2 3])
``````

So why do we need `for` function? It really shows its value when you are working with multiple collections

``````(for [number [1 2 3]
letter [:a :b :c]]
(str number letter))
``````

Again we could use `map` function for this as follows

``````(mapcat (fn [number] (map (fn [letter] (str number letter)))))
``````

So with the `for` function we can do the same calculation with much easier code to reason about.

## Filtering results with predicatesλ︎

With the `for` function we can add a filter on the results by using a predicate, to test if a condition is true or false. Any values that meet the condition as true are returned, values that are false are omitted.

``````(for [x (range 10) :when (odd? x)] x)

(for [x (range 10) :while (even? x)] x)
``````

To do this kind of filtering with maps would be possible, however the code would be harder for humans to parse and understand.

Note Create a 3-tumbler combination padlock, with each tumbler having a range of 0 to 9. Count the number of possible combinations. Then add a predicate that filters out some of the combinations

Lets just model all the possible combinations

``````(for [tumbler-1 (range 10)
tumbler-2 (range 10)
tumbler-3 (range 10)]
[tumbler-1 tumbler-2 tumbler-3])
``````

Now lets count the combinations

``````(count (for [tumbler-1 (range 10)
tumbler-2 (range 10)
tumbler-3 (range 10)]
[tumbler-1 tumbler-2 tumbler-3]))
``````

Now add a predicate using `:when` to filter out the combinations that do not match.

``````(count (for [tumbler-1 (range 10)
tumbler-2 (range 10)
tumbler-3 (range 10)
:when (or (= tumbler-1 tumbler-2)
(= tumbler-2 tumbler-3)
(= tumbler-3 tumbler-1))]
[tumbler-1 tumbler-2 tumbler-3]))
``````

Note Create a 2 character prefix for tickets, using capital letters from the English alphabet. However, exclude I and O as they can be mistaken for numbers

Lets just model all the possible combinations

``````(for [letter-1 capital-letters
letter-2 capital-letters
:when (and (not (blacklisted letter-1))
(not (blacklisted letter-2)))]
(str letter-1 letter-2))
``````

Last update: April 25, 2023