Skip to content

Instantly share code, notes, and snippets.

@looselytyped
Created August 10, 2013 15:36
Show Gist options
  • Save looselytyped/6200860 to your computer and use it in GitHub Desktop.
Save looselytyped/6200860 to your computer and use it in GitHub Desktop.

Destructuring Composite Data

Problem

You want to destructure a sequential (e.g. list, vector) or an associate (map) collection.

Solution

Use Clojure’s sequential destructuring to easily destructure a list

(def breakfast-list '("coffee" "toast"))
;; -> #'user/breakfast-list
user> (let [[drink food] breakfast-list]
  (str "I had " drink " and " food " for breakfast"))
;; -> "I had coffee and toast for breakfast"

You can do the same with vectors since they are a part of the ``sequential'' abstraction.

(def breakfast-vector ["coffee" "toast"])
;; -> #'user/breakfast-vector
(let [[drink food] breakfast-vector]
  (str "I had " drink " and " food " for breakfast"))
;; -> "I had coffee and toast for breakfast"

You can destructure as few or as many values from the sequential collection as desired. If the destructuring vector contains less names than the collection being destructured Clojure will simply ignore the rest.

(def breakfast-vector ["coffee" "toast" "danish"])
;; -> #'user/breakfast-vector

;; only destructure the first two
(let [[drink food] breakfast-vector]
  (str "I had " drink " and " food " for breakfast"))
;; -> "I had coffee and toast for breakfast"

On the other hand if the destructuring vector contains more than the collection being destructured those names will be set to nil

;; two item vector
(def breakfast-vector ["coffee" "toast"])
;; -> #'user/breakfast-vector

;; destructuring 3 items
(let [[drink food desserts] breakfast-vector]
  desserts)
;; -> nil

You can capture the remaining items in the collection (those are the values not being destructured) into a seq using &.

(def breakfast-vector ["coffee" "toast" "danish"])
;; -> #'user/breakfast-vector

(let [[drink food & desserts] breakfast-vector]
  (str "I had " drink " and " food " for breakfast with " (count desserts) " desserts"))
;; -> "I had coffee and toast for breakfast with 1 desserts"

If you would like to name the original collection along with destructuring you can do that with as

(def breakfast-vector ["coffee" "toast" "danish"])
;; -> #'user/breakfast-vector

(let [[drink :as all] breakfast-vector]
  (str "Including " drink " I had " (count all) " items for breakfast"))
"Including coffee I had 3 items for breakfast"

You can mix and match all of the above. It is idiomatic to denote unused indexes with a _

(def breakfast-vector ["coffee" "toast" "danish"])
;; -> #'user/breakfast-vector

(let [[_ food & rest :as all] breakfast-vector]
  (str "I had " food " along with " (count rest) " desserts totalling " (count all) " items for breakfast"))
"I had toast along with 1 desserts totalling 3 items for breakfast"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment