# 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))