August 18, 2018

Just Juxt #4: Duplicate a Sequence (4clojure #32)

Dupe a seq with juxt

Write a function which duplicates each element of a sequence.

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 dupseq [s]
  )

(deftest test-32
  (is (= (dupseq [1 2 3]) '(1 1 2 2 3 3)))
  (is (= (dupseq [:a :a :b :b]) '(:a :a :a :a :b :b :b :b)))
  (is (= (dupseq [[1 2] [3 4]]) '([1 2] [1 2] [3 4] [3 4])))
  (is (= (dupseq [44 33]) [44 44 33 33])))
  
(run-tests)

Here's the most common solution:

(defn dupseq [s]
  (interleave s s))
  
(run-tests)

Recall the docstring for interleave:

user=> (doc interleave)
-------------------------
clojure.core/interleave
([] [c1] [c1 c2] [c1 c2 & colls])
  Returns a lazy seq of the first item in each coll, then the second etc.

It's a fine solution, but I could argue that the intent behind interleaving a seq with itself is un-juxt-ified. Ha ha. But seriously... what if we (or the client) were to change our minds, and instead want to duplicate the seq but with some sort of transformation on the repeat. Not so far fetched...

We would have to rewrite the function!!

What if we could write it in such a way that we could more clearly adjust our transmogrifier settings:

Well... it turns out there is a way!! Here's the juxt-ification:

(defn dupseq [s]
  (mapcat (juxt identity identity) s))
  
(run-tests)

That's better! Now let's say we wanted to duplicate a list of numbers but increment the second group. We can easily change the second function passed to juxt:

(defn dupe-inc [s]
  (mapcat (juxt identity inc) s))
  
(dupe-inc '(1 1 2 2 3 3))

Pretty cool, huh? I would say that's a much more useful function!

Tags: coding exercises KLIPSE 4clojure Cryogen juxt