What is the difference between butlast
and drop-last
in Clojure ?
Is it only the laziness ? Should I should prefer one over the other ?
also, if you need to realize the whole collection, butlast
is dramatically faster, which is logical if you look at their source:
(def
butlast (fn ^:static butlast [s]
(loop [ret [] s s]
(if (next s)
(recur (conj ret (first s)) (next s))
(seq ret)))))
(defn drop-last
([s] (drop-last 1 s))
([n s] (map (fn [x _] x) s (drop n s))))
so drop-last
uses map
, while butlast
uses simple iteration with recur
. Here is a little example:
user> (time (let [_ (butlast (range 10000000))]))
"Elapsed time: 2052.853726 msecs"
nil
user> (time (let [_ (doall (drop-last (range 10000000)))]))
"Elapsed time: 14072.259077 msecs"
nil
so i wouldn't blindly prefer one over another. I use drop-last
only when i really need laziness, otherwise butlast
.
Yes, laziness as well as the fact that drop-last
can take also take n
, indicating how many elements to drop from the end lazily.
There's a discussion here where someone is making the case that butlast
is more readable and maybe a familiar idiom for Lisp programmers, but I generally just opt to use drop-last
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With