!

• List

• Vector

• (Hash-) Map

• Set

# List

Create

• (...)
• (list ...)

• (first seq)
• (nth seq n)

Transformation

• (cons elem seq)
• (conj seq elem ...)
• (rest seq)

# Vector

!

Create

• [ ... ]
• (vector ...)
• (vec seq)
• (into v seq)

• (v n)
• (get v n)
• (nth v n), (first ...) still apply.

!

Transformation

• conj, cons, rest still apply.
• (assoc v n val)
• (update v n func)
• (subvec v start end)
• (replace map v)

# (Hash-) Map

!

Create

• { ... }
• (hash-map ...)
• (array-map ...)

Read: maps are functions, and keywords are functions!!

• (m key)
• (:keyword m)
• (get m key default-val)
• (keys m)
• (vals m)
• (contains? m key)

!

Transform

• (assoc m key val)
• (assoc-in m [path] val)
• (dissoc m key)
• (merge m1 m2 ...)
• (merge-width f m1 m2 ...)
• (select-keys m [keys])
• (update m key func)
• (update-in m [path] func)
• (rename-keys m rename-map)

!

# Sequences

• Think of it as another data structure, known as seq.
• The closest thing we have seen is Iterable in Java.

!

Seqs gets the most amount attention in Clojure.

# Sources of seqs

(range <start> <end> <step>)


! Creates a sequence of integers.

(repeat <n> <x>)
(repeat <x>)


! Creates a sequence of the same value x repeately n times. If n is omitted, the sequence continuous forever.

(iterate <f> <x>)


! A sequence with: x (f x), (f (f x)), … forever.

(repeatedly <n> <f>)
(repeatedly <f>)


! A sequence with: (f), (f), … $n$ times. If $n$ is omitted, the sequence continuous forever.

(cycle <collection>)


! Generates an infinite sequence of by repeating the collection forever.

# More sources of seqs

(clojure.java.io/reader <filename>)


## Creating a sequence of lines

(line-seq <rdr>)


### Note

Don’t forget to close the reader when you are done. To be safe, use the macro:

(with-open [rdr (clojure.java.io/reader <filename>)]
(let [lines (line-seq rdr)]
...))


! The with-open macro will create the symbol binding to the opened reader, and close it afterwards.

# Even more sources of seqs

## Regular expression

#"..."


! Clojure relies on Java’s regular expression library. So the syntax for regular expressions is the same as Java’s java.util.regex library. But creating a pattern is really simple with the reader macro #"..."

## Sequences of matches

(re-seq <pattern> <string>)


! Returns a sequence of matches of pattern in the string. If the pattern does not contain groups, then each match is a string. Otherwise, it’s a vector containing the groups.

# Working with seqs

(def nat (iterate inc 0))


! Defining natural numbers. This is an infinite sequence, so (println nat) will result in a never-ending loop.

(def nat+ (rest nat))
; (1 2 3 4 5 ... ∞)


! Strictly positive numbers

(first nat)   ; 0
(first nat+)  ; 1


! Getting the first element

(take 10 nat)
; (0 1 2 3 4 5 6 7 8 9)


! Takes the first 100 natural numbers.

# Working with seqs

(interleave <seq1> <seq2>)


! Mix two sequences into one by interleaving the elements.

(interpose <x> <seq>)


! Insert <x> between the elements in <seq>.

(split-at <index> <seq>)


! Returns a vector containing two seqs. The two seqs are produced by splitting the input <seq> at the <index>.

# Higher order functions with seqs

(map <fn> <seq>)


! Returns a sequence by applying (<fn> x) for each x in <seq>.

(map <fn> <seq-1> <seq-2>)


! Returns a sequence by applying (<fn> xi yi) for each xi in <seq-1> and yi in <seq-2>.

(filter <pred> <seq>)


! The function <pre> is a predicate, namely a function that always returns true/false. The returned seq contains elements
x$\in$<seq> that satisfies the predicate, i.e. (<pred> x) is true.

(reduce <f> <seq>)
(reduce <f> <x0> <seq>)


! Reduces a sequence (x1 x2 x3) to a single value of
(f (f (f x0) x1) x3).

# More higher order functions on seqs

(take-while <pred> <seq>)


! Takes elements x from <seq> for as long as (<pred> x) is true.

(drop-while <pred> <seq>)


! Drops elements x from <seq> for as long as (<pred> x) is true. Returns the remaining elements.

(split-with <pred> <seq>)


! Returns a vector of two seqs. The first is (take-while ...) and the second is (drop-while ...).

# Predicates on seqs

(every? <pred> <seq>)


! Tests if pred holds for every element of the seq.

(some <pred> <seq>)


! Returns the first element in seq that satisfies the predicate. It can be used to test if pred holds for some element of the seq.

(not-every? <pred> <seq>)


! Test that predicate is violated by some elements in seq.

(not-any? <pred> <seq>)


! Test that none of the elements in seq satisfies the predicate.

# Transformations of seqs

(sort <seq>)
(sort <cmp> <seq>)


! Sorts the seq by an optional comparator.

(sort-by <key-fn> <seq>)
(sort-by <key-fn> <cmp> <seq>)


! Sorts the seq by (<key-fn> x) instead of the elements x.

(reverse seq)


! Reverses the sequence.

# Seq in action

(def nat (iterate inc 0))

(defn even? [n] (zero? (mod n 2)))


# Seq in action

(def even-nat (filter even? nat))

(def odd-nat (filter #(not (even? %1)) nat))

(take 4 even-nat)       ; (0 2 4 6)
(take 4 odd-nat)        ; (1 3 5 7)

(interleave odd-nat even-nat)
; => (1 0 3 2 5 4 7 6)


# Seq in action

(defn prime? [n] (not-any? (fn [i] (zero? (mod n i))) (range 2 n)))

(def primes (filter prime? (drop 2 nat)))

(take 100 primes)


Questions:

1. Does the gap between two adjacent primes grow?
2. How many primes $\leq n$ are there for growing n?

# Tricks & Magic

## The trick

(def letters [\a \b \c])
(def numbers [ 1  2  3   4  5  6])
(map vector letters numbers)
; => ([\a 1] [\b 2] [\c 3])


## The magic

(def prime-gaps
(map #(apply - (reverse %)) (map vector primes (rest primes))))


# Tricks & Magic

(defn count-primes [n] (count (take-while #(<= % n) primes)))

(def prime-counts (map count-primes nat))


!

Theorem:

The distribution of primes is $\Theta(n/\log n)$.

!

(defn g [n] (if (> n 1) (/ (float n) (Math/log n)) 1))
(def alpha (map #(/ %1 (g %2)) prime-counts nat))


# A preview of the leverage on JVM

You need to include incanter.jar in the CLASSPATH to run the following code.

(use '(incanter core charts))
(let [ds (conj-cols (take 1000 nat) (take 1000 alpha))]
(view (xy-plot 0 1 :data ds)))


# More sorcery

(view
(scatter-plot 0 1
:data (conj-cols
(take 1000 nat)
(take 1000 prime-gaps))))


# In one fell swoop

(use '(incanter core charts))
(let [; list of natural numbers
nat (iterate inc 0)
; a predicate to decide of input is prime
prime? (fn [n]
(not-any?
(fn [i] (zero? (mod n i)))
(range 2 n)))
; list of primes
primes (filter prime? nat)
; compute the gaps between to adjacent primes
gaps (map
#(apply - (reverse %))
(map vector primes (rest primes)))
; counts the number of primes less than n
countp (fn [n] (count (take-while #(< % n) primes)))]
; plots
(view (scatter-plot 0 1 :data (conj-cols (take 1000 nat) (take 1000 gaps))))
(view (xy-plot 0 1 :data (conj-cols (take 1000 nat)
(map #(* (Math/log %) (/ (countp %) (float %)))
(take 1000 nat))))))


# Summary

!

• Data
• Data transformation
• Sequences
• Sequence (higher-order) functions