Sequences
Create a sequence from a collection:
(seq [1 2 3]) ; (1 2 3)
(seq '("foo" "bar" "qux")) ; ("foo" "bar" "qux")
(seq #{1 2 4}) ; (1 4 2)
(seq {:a 3 :b 7 :c 5}) ; ([:a 3] [:b 7] [:c 5])
Despite the round parentheses in the output, sequences are not lists.
Create a sequence from an empty colleection:
(seq []) ; nil
(seq '()) ; nil
(seq #{}) ; nil
(seq {}) ; nil
Returning nil
(falsy) instead of an empty sequence (truthy) is
useful in conditions.
Get the first element, all but the first element, and the rest of a sequence:
(first (seq [1 2 3])) ; 1
(next (seq [1 2 3])) ; (2 3)
(rest (seq [1 2 3])) ; (2 3)
Applied to an empty sequence, both first
and next
return nil
(truthy), whereas rest
returns an empty sequence (falsy):
(first (seq [])) ; nil
(next (seq [])) ; nil
(rest (seq [])) ; ()
Add a new element to the front of a square:
(cons 0 (seq [1 2 3])) ; (0 1 2 3)
Sort and reverse a collection:
(sort [9 4 6 2 1]) ; (1 2 4 6 9)
(reverse [2 4 8 16]) ; (16 8 4 2)
Partition a collection into smaller junks:
(partition 2 [0 1 2 3 4 5]) ; ((0 1) (2 3) (4 5))
Weave two collections together:
(def odd [1 3 5 7])
(def even [2 4 6 8])
(interleave odd even) ; (1 2 3 4 5 6 7 8)
Insert a separator in between elements:
(interpose "," [1 2 3 4]) ; (1 "," 2 "," 3 "," 4)
Those functions turn a collection into a sequence first. Such collections are said to be seqable, i.e. they can be turned into a sequence.
Filter a collection using a predicate:
(filter #(= (mod % 2) 0) [0 1 2 3 4 5]) ; (0 2 4)
Check whether or not a predicate holds true for at least one element:
(some #(= (mod % 2) 0) [0 1 2 3 4 5]) ; true
(some #(= ( mod % 2) 0) [1 3 5 7]) ; nil
Transform the elements of a collection:
(map #(* % 2) [0 1 2 3]) ; (0 2 4 6)
Compose functions:
(def twice-the-successor (comp #(* % 2) #(+ % 1)))
(twice-the-successor 3) ; 8
(map twice-the-successor [0 1 2 3]) ; (2 4 6 8)
Executing ((comp f g) x)
is equivalent to (f (g x))
.
Process a collection in a loop:
(for [x [1 2 3]] (* x 2)) ; (2 4 6)
Combine the elements of a collection to a single value:
(reduce (fn [acc x] (* acc x)) [1 2 3 4]) ; 24
Provide an initial accumulator value (instead of using the first element):
(reduce (fn [acc x]
(if (= (mod x 2) 0)
(assoc acc :even (+ (:even acc) 1))
(assoc acc :odd (+ (:odd acc) 1))))
{:even 0 :odd 0}
[0 1 2 3 4 8 16]) ; {:even 5, :odd 2}
The {:even 0 :odd 0}
map (second argument) becomes the initial
acc
.
Exercises
Compose Function
Write a function compose
that expects a vector functions as its
argument. The function shall return another function expecting a
single argument that first applies the last given function, then
applies its result to the second-last given function, etc.
Hint: Use last
and butlast
to separate the last element from the
rest of a collection. If no functions are passed, just return the
identity
function.
Test: ((compose [#(- % 1) #(* % 2) #(+ % 1)]) 5)
shall return 11
.
Sequence Count
Write a function seq-count
that accepts a vector, a list, a set, or
a map, and returns the number of elements in the given collection.
Hint: Convert the collection to a sequence first and use next
to
traverse the sequence.
Test: (seq-count [])
shall return 0, (seq-count [1 2 3])
shall
return 3, and (seq-count [nil nil])
shall return 2.
Parse Numbers
Given a collection of numbers, booleans, strings, and elements of
other types, write a function as-nums
that returns a sequence of
numbers as follows:
- Numbers shall be retained as they are,
- booleans shall be converted to
1
(true
) or0
(false
), - and strings shall be parsed to floating point numbers.
Strings that cannot be parsed as a number or elements of any other type can be ignored and won’t end up in the returned sequence.
Hint: Use Float/parseFloat
to parse the strings. Handle a possible
NumberFormatException
.
Test: (as-nums [3 2.5 true true false "1.25" "hey" :ho nil 7])
shall
return (3 2.5 1 1 0 1.25 7)
.
Longest Songs
Given a vector of songs:
(def songs [{:name "Pale Fire" :duration "4m17s"}
{:name "Monument" :duration "6m34s"}
{:name "The Ivory Gate of Dreams" :duration "21m58s"}
{:name "Still Remains" :duration "16m8s"}
{:name "The Ghosts of Home" :duration "10m31s"}
{:name "Glass Houses" :duration "3m35s"}
{:name "Guardian" :duration "7m33s"}
{:name "Exodus" :duration "8m39s"}])
Write a function longest
that accepts a positive numeric parameter
n
, a collection of songs, and returns the n
longest songs
formatted as a string.
Hint: Write a helper function parse-duration
that converts the
duration into a number of seconds. Use regular expressions with
re-matcher
and
re-find
for that
purpose. Use sort-by
and reverse
to sort the result in descending
order, take
to extract the first n
elements, and interpose
to
format the output.
Test: (longest 3 songs)
shall return "1) The Ivory Gate of Dreams | 2) Still Remains | 3) The Ghosts of Home"
.
Pointy Arrow Refactoring
Rrefactor the longest
function from the last exercise using the
pointy arrow operator ->>
Hint: The ->>
operator takes the return value from a function, and
hands it down to the next function as its last parameter. The range
function creates a sequence starting from the first parameter
(inclusive) up to the second parameter (exclusive). Use interleave
and partition
to combine two sequences.
Test: Same as in last exercise.