Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Clojure, how to destructure all the keys of a map?

Tags:

clojure

In clojure, it is possible to destructure some keys of a map like this:

(let [{:keys [cpp js]} {:cpp 88 :js 90}] 
   (println js); 90
   (println cpp); 88
 )

Is there a way to destructure all the keys of a map?

Maybe something like:

(let [{:all-the-keys} {:cpp 88 :js 90}] 
   (println js); 90
   (println cpp); 88
 )
like image 569
viebel Avatar asked Feb 18 '12 23:02

viebel


People also ask

What is a map in CL Clojure?

Clojure - Maps. A Map is a collection that maps keys to values. Two different map types are provided - hashed and sorted. HashMaps require keys that correctly support hashCode and equals. SortedMaps require keys that implement Comparable, or an instance of Comparator.

Is it possible to pass alternating key→values between mappings in Clojure?

However, in Clojure 1.11 the capability was added to allow passing of alternating key→values, or a map of those same mappings, or even a map with key→values before it to functions expecting keyword arguments. Therefore, the call to configure above can take any of the following forms in addition to those shown above:

What are the different types of destructuring in Clojure?

Clojure destructuring is broken up into two categories, sequential destructuring and associative destructuring. Sequential destructuring represents a sequential data structure as a Clojure vector within a let binding.

What happened to keyword arguments in Clojure?

The use of keyword arguments had fallen in and out of fashion in the Clojure community over the years. They are now mostly used when presenting interfaces that people are expected to type at the REPL or the outermost layers of an API. In general, inner layers of the code found it easier to pass options as an explicit map.


2 Answers

Not really, and it wouldn't be a good idea. Imagine:

(let [{:all-the-keys} m]
  (foo bar))

Are foo and bar globals? Locals? Keys you should extract from m? What should this code do if m sometimes contains a foo key, and foo is also a global function? Sometimes you call the global, and sometimes you call the function stored in m?

Ignoring the technical problems (which could be overcome), it is really a disaster for readability and predictability. Just be explicit about what keys you want to pull out; if you frequently want to pull out the same ten keys, you can write a simple macro like (with-person p body) that simplifies that common case for you.

like image 60
amalloy Avatar answered Oct 01 '22 17:10

amalloy


This question is pretty old so you've probably forgotten about it, but it came up on google when I was trying to do the same thing, so if I post my solution it might help someone else out.

(defmacro let-map [vars & forms]
  `(eval (list 'let (->> ~vars keys
                         (map (fn [sym#] [(-> sym# name symbol) (~vars sym#)]))
                         (apply concat) vec)
               '~(conj forms 'do))))

This basically transforms the map {:cpp 88 :js 90} into the binding form [cpp 88 js 90] then constructs a let binding, along with performing some eval-jitsu to make sure that this happens at run time.

(def test-map {:cpp 88 :js 90})
(let-map test-map
  (println js)
  (println cpp))
;=> 90
;=> 88
like image 24
one-more-minute Avatar answered Oct 01 '22 18:10

one-more-minute