I have a record:
(defrecord Point [x y])
(def p (Point. 1 2))
Now I want to extract just the map from the record. These ways get the job do
A. Webb suggested the much-simpler (into {} p)
in the comments. Thanks!
Here is a code snippet that is more general; it works for recursive records:
(defrecord Thing [a b])
(def t1 (Thing. 1 2))
(def t2 (Thing. 3 4))
(def t3 (Thing. t1 t2))
(defn record->map
[record]
(let [f #(if (record? %) (record->map %) %)
ks (keys record)
vs (map f (vals record))]
(zipmap ks vs)))
(record->map t3)
; {:b {:b 4, :a 3}, :a {:b 2, :a 1}}
Records are maps
(defrecord Thing [a b])
(def t1 (Thing. 1 2))
(instance? clojure.lang.IPersistentMap t1) ;=> true
So, in general there is no need to coerce them into a APersistentMap
type. But, if desired you do so with into
:
(into {} t1) ;=> {:a 1, :b 2}
If you want to traverse an arbitrary data structure, including nested records, making this transformation, then use walk
(def t2 (Thing. 3 4))
(def t3 (Thing. t1 t2))
(def coll (list t1 [t2 {:foo t3}]))
(clojure.walk/postwalk #(if (record? %) (into {} %) %) coll)
;=> ({:a 1, :b 2} [{:a 3, :b 4} {:foo {:a {:a 1, :b 2}, :b {:a 3, :b 4}}}])
I also wrote a general function that converts records to maps for (most) arbitrary Clojure data structures:
(defn derecordize
"Returns a data structure equal (using clojure.core/=) to the
original value with all records converted to plain maps."
[v]
(cond
(record? v) (derecordize (into {} v))
(list? v) (map derecordize v)
(vector? v) (mapv derecordize v)
(set? v) (set (map derecordize v))
(map? v) (zipmap (map derecordize (keys v)) (map derecordize (vals v)))
:else v))
I know this is unusual. This is useful when you need to export a data structure without records.