Dark theme | Light theme

October 30, 2022

Clojure Goodness: Getting But The Last Element(s) From A Collection

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.