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

Couldnt we just do this with map? Yes, we could.

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

So why to 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` funciton 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 ommitted.

``````(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 more 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 mistakend for numbers

``````(for [letter-1 capital-letters