Just Juxt #5: Replicate a Sequence (4clojure #33)
Write a function which replicates each element of a sequence a variable number of times.
Here's a live testing area for you to play with. See if you can solve it with juxt
. Then check out the answer below!
(ns live.test
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
(defn replicate [s n]
)
(deftest replicate-test
(is (= (replicate [1 2 3] 2) '(1 1 2 2 3 3)))
(is (= (replicate [:a :b] 4) '(:a :a :a :a :b :b :b :b)))
(is (= (replicate [4 5 6] 1) '(4 5 6)))
(is (= (replicate [[1 2] [3 4]] 2) '([1 2] [1 2] [3 4] [3 4])))
(is (= (replicate [44 33] 2) [44 44 33 33])))
(run-tests)
Here's the most common solution:
(defn replicate [s n]
(mapcat (partial repeat n) s))
(run-tests)
And here's the juxt
-ification:
(defn replicate [s n]
(mapcat (apply juxt (repeat n identity)) s))
(run-tests)
To get a closer look, let's plug in the args from our first test case:
(mapcat (apply juxt (repeat 2 identity)) [1 2 3])
This example is deceptively more clever than the ones we've done so far, because we are using apply juxt
. Try to wrap your head around that for a second. We're applying a fn, which takes a set of fns, and applies that.
This can be better understood in the context of yesterday's example, to duplicate a seq:
(mapcat (juxt identity identity) [1 2 3])
What we are doing now is using repeat
to determine how many identity
s are passed to juxt
. Here it is with 3:
(mapcat (juxt identity identity identity) [1 2 3])
Which is equivalent to:
(mapcat (apply juxt (repeat 3 identity)) [1 2 3])
The reason we need to use apply
is that repeat
returns a seq, but juxt
is asking for functions.
I think it's great how these problems build upon each other. Duplication is a special case of replication.
Tune in tomorrow and we'll see what other dials we can add to our transmogrifier. Until then, I hope your day becomes juxt
ed with many wonderful things!