10

What is the difference between butlast and drop-last in Clojure ?

Is it only the laziness ? Should I should prefer one over the other ?

nha
  • 17,623
  • 13
  • 87
  • 133

2 Answers2

12

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.

leetwinski
  • 17,408
  • 2
  • 18
  • 42
4

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.

lsankar4033
  • 509
  • 3
  • 14