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