When we want to get elements from a collection, but not the last element(s), we can use the function butlast and drop-last. The function butlast returns all elements before the last element. If we use the function on an empty collection we get back a nil result. When we use the function drop-last we get back a lazy sequence. Also we can use an extra argument for the function to indicate how many of the last elements we don't want in the result. If we use drop-last on an emtpy collection we get back an empty lazy sequence.
In the following example we use both functions with several collections:
(ns mrhaki.core.butlast
(:require [clojure.test :refer [is]]))
;; Sample vector with some JVM langauges.
(def languages ["Clojure" "Groovy" "Java"])
;; Sample map describing a user.
(def user {:alias "mrhaki" :first "Hubert" :last "Klein Ikkink" :country "The Netherlands"})
;; Using butlast to get all elements but
;; not the last element as a sequence.
(is (= '("Clojure" "Groovy") (butlast languages)))
;; We can also use butlast on a map, the result
;; is a sequence with vectors containing the
;; key/value pairs from the original map.
(is (= '([:alias "mrhaki"] [:first "Hubert"] [:last "Klein Ikkink"])
(butlast user))
;; We can use the into function to transform this
;; into a map again.
(= {:alias "mrhaki" :first "Hubert" :last "Klein Ikkink"}
(into {} (butlast user))))
;; Returns nil when collection is empty.
(is (= nil (butlast [])))
;; drop-last returns a lazy sequence with all
;; elements but the last element.
(is (= '("Clojure" "Groovy") (drop-last languages)))
;; Returns an empty sequence when collection is empty.
(is (= '() (drop-last [])))
;; We can use an extra argument with but-last
;; to indicate the number of items to drop
;; from the end of the collection.
;; butlast cannot do this.
(is (= ["Clojure"] (drop-last 2 languages)))
;; drop-last works on maps just like butlast.
(is (= '([:alias "mrhaki"]) (drop-last 3 user))
(= {:alias "mrhaki"} (into {} (drop-last 3 user))))
Written with Clojure 1.11.1.