从Clojure记录返回普通映射
我有一个记录:从Clojure记录返回普通映射,clojure,records,Clojure,Records,我有一个记录: (defrecord Point [x y]) (def p (Point. 1 2)) 现在我只想从记录中提取地图。这些方法可以完成工作。这些是好方法吗?有更好的方法吗 (into {} (concat p)) (into {} (map identity p)) (apply hash-map (apply concat p)) 我希望有一种更干净的方法,也许是内置于记录的概念中。建议在注释中使用更简单的(into{}p)。谢谢 下面是一个更一般的代码片段;它适用于递归记
(defrecord Point [x y])
(def p (Point. 1 2))
现在我只想从记录中提取地图。这些方法可以完成工作。这些是好方法吗?有更好的方法吗
(into {} (concat p))
(into {} (map identity p))
(apply hash-map (apply concat p))
我希望有一种更干净的方法,也许是内置于记录的概念中。建议在注释中使用更简单的(into{}p)
。谢谢
下面是一个更一般的代码片段;它适用于递归记录:
(记录事物[ab])
(定义t1(事物1.2))
(def t2(Thing.3.4))
(def t3(Thing.t1 t2))
(defn记录->地图
[纪录]
(让[f#)(如果(记录?%)(记录->映射%)
ks(钥匙记录)
vs(地图f(VAL记录))]
(zipmap ks vs)))
(记录->地图t3)
; {:b{:b 4,:a 3},:a{:b 2,:a 1}
我还编写了一个通用函数,用于将(大多数)任意Clojure数据结构的记录转换为映射:
(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))
我知道这很不寻常。当您需要导出没有记录的数据结构时,这非常有用。记录是映射
因此,通常不需要将它们强制为apResistentMap
类型。但是,如果需要,可以将转换为:
(into {} t1) ;=> {:a 1, :b 2}
如果要遍历任意数据结构(包括嵌套记录),进行此转换,请使用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}}}])
你为什么要这么做?记录已经是持久映射的实现了。是的,我知道记录可以完成映射可以完成的所有事情。我还是想做。想法?这是更好的答案(轻推)!我只是浏览了一下,但没有找到内置的Java方法。(clojure.walk/postwark#(if(record?%)(into{}%)%)t3)
a.韦伯:这是一个更好的答案。想发布吗?这就是walk
所做的。它了解任意数据结构、列表、向量、地图、集合。。。包括记录。此外,您基本上不应该调用list?
-您的意思是在这种情况下使用seq?
(与大多数情况一样)。例如,(对于[x(范围5)](MyRecord.x))
,您建议的解决方案不起作用。谢谢!我的用例是“映射”数据结构中的记录,以紧凑的方式序列化,使测试更具可读性。(Clojure的默认记录序列化非常详细,特别是当您有类型提示并使用print dup
)@DavidJames((get-method-print-method-java.util.Map)(Thing.1 2)*out*);=>{:A1,:B2}
(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}}}])