I'm resolving a 4Clojure exercise, this exercise asks you to build your own interpose function. My answer follows:
(fn my-interpose
([separator input] (my-interpose separator input nil))
([separator input result]
(if
(empty? input)
(reverse (rest result))
(my-interpose separator (rest input) (cons separator (cons (first input) result))))))
I'm doing these exercises to learn the language a开发者_高级运维s I read a Clojure book. I will like to know the opinion about my code of people with an experience in the language. Could I avoid the reverse call? Are there any conventions I'm breaking hardly with this kind of code?
What you have is a good proper starting point :). Excellent work.
Starting with what you have you may want to:
Replace your recursive call with a call to
recur
because as written it will hit a stack overflow(defn foo [stuff] (dostuff ... ) (foo (rest stuff)))
becomes:
(defn foo [stuff] (dostuff ...) (recur (rest stuff)))
to avoid blowing the stack. this then often becomes:
(map dostuff stuff)
Replace the recustion entirely with the
for
function(for [a one-list b another-list] (dont-give-away-the-answer))
Yes you can avoid the reverse call,
(defn my-interpose [sep coll]
(when (seq coll)
(lazy-cat [(first coll) sep]
(my-interpose sep (rest coll)))))
as arthur suggest you can use recur in order to not to blow the stack but 99% of the time you don't need it.
EDIT:
This is a bit cleaner,
(defn my-interpose [sep coll]
(if-let [[first & rest] coll]
(lazy-cat [first sep] (my-interpose sep rest))))
Got to various answers using mapcat and for but in the end I found this:
#(rest (interleave (repeat %1) %2))
Where the first argument is the separator and the second is the collection. Just posting this answer for pure curiosity of other Clojure noobs like me.
Here is my solution, trying to rely on lower-level lisp or scheme-like functions.
(defn my-interpose[sep coll]
(letfn [(f [c]
(when-not (empty? c)
(cons sep (cons (first c)
(f (next c))))))]
(next (f coll))))
You may want to use map
(defn my-interpose [sep coll]
(rest (apply concat (map #(vector sep %) coll))))
or a directly a reduce and compute the answer as you go
(defn my-interpose [sep coll]
(rest (reduce #(conj %1 sep %2) [] coll)))
The idea behind this is to compute a sequence like (sep x0 sep x1 sep x2 ... sep xn)
and then skip the first element to get (x0 sep x1 sep x2 ... xn)
.
Using just reduce and conj:
(defn my-interpose [sep a-seq]
(if (empty? a-seq)
a-seq
(reduce (fn [e1 e2] (if (empty? e1)
(conj e1 e2)
(conj e1 sep e2))) [] a-seq)))
精彩评论