在Clojure/EDN中序列化已排序的映射?
如何在Clojure中序列化和反序列化排序映射 例如:在Clojure/EDN中序列化已排序的映射?,clojure,sortedmap,edn,Clojure,Sortedmap,Edn,如何在Clojure中序列化和反序列化排序映射 例如: (sorted-map :a 1 :b 2 :c 3 :d 4 :e 5) {:a 1, :b 2, :c 3, :d 4, :e 5} 我注意到: 在REPL中,已排序的映射以与未排序的映射相同的方式显示。这有时似乎很方便,但有时却不方便 不支持 Clojure确实支持 额外资源: 同一个问题有两个可用的答案: 第三个答案是设置自定义读取器文本。您可以像这样打印排序后的地图 ;; non-namespaced tags are m
(sorted-map :a 1 :b 2 :c 3 :d 4 :e 5)
{:a 1, :b 2, :c 3, :d 4, :e 5}
我注意到:
;; non-namespaced tags are meant to be reserved
#my.ns/sorted-map {:foo 1 :bar 2}
然后在读取时使用适当的数据函数(从哈希映射转换为排序映射)。您可以选择是否处理定制比较器(这是一个一般情况下无法解决的问题,但您当然可以选择处理特殊情况)
clojure.edn/read
接受可选的opts
映射,该映射可能包含:reader
键;然后,该键处的值将被视为一个映射,指定哪些数据读取器用于哪些标记。有关详细信息,请参见(doc clojure.edn/read)
至于打印,您可以为print method
安装自定义方法,或使用自定义功能打印已排序的地图。我可能会选择后一种解决方案——为内置类型实现内置协议/多方法通常不是一个好主意,因此即使在特定情况下看起来合理,也需要额外的注意等等。;使用自己的功能更简单
更新:
演示如何重新使用IPersistentMap
的打印方法
impl clean,正如在对David回答的评论中承诺的那样:
(def ^:private ipm-print-method
(get (methods print-method) clojure.lang.IPersistentMap))
(defmethod print-method clojure.lang.PersistentTreeMap
[o ^java.io.Writer w]
(.write w "#sorted/map ")
(ipm-print-method o w))
有了这一点:
user=> (sorted-map :foo 1 :bar 2)
#sorted/map {:bar 2, :foo 1}
在
数据读取器.clj
中:
{sorted/map my-app.core/create-sorted-map}
注:我希望这能起作用,但没有(不确定原因):
现在,在我的app.core中:
(defn create-sorted-map
[x]
(clojure.lang.PersistentTreeMap/create x))
(defmethod print-method clojure.lang.PersistentTreeMap
[o ^java.io.Writer w]
(.write w "#sorted/map ")
(print-method (into {} o) w))
作为另一种选择--低级别,您可以使用:
(defn create-sorted-map [x] (into (sorted-map) x))
测试:
(deftest reader-literal-test
(testing "#sorted/map"
(is (= (sorted-map :v 4 :w 5 :x 6 :y 7 :z 8)
#sorted/map {:v 4 :w 5 :x 6 :y 7 :z 8}))))
(deftest str-test
(testing "str"
(is (= "#sorted/map {:v 4, :w 5, :x 6, :y 7, :z 8}"
(str (sorted-map :v 4 :w 5 :x 6 :y 7 :z 8))))))
大部分内容都是根据我在上面找到的资源改编的
注:我很惊讶上面的
打印方法
有效。在我看来,(into{}o)
将失去顺序,从而导致打印失败,但它在我的测试中起作用。我不知道为什么。NB。clojure 1.5中引入了clojure.edn
名称空间。测试通过是因为它们很小,所以基本上是“偶然的”(clojure的实现细节)。(测试的大小很重要,因为对于小映射(into{}…
创建数组映射,保留插入顺序。当它们足够大时,这些映射将转换为哈希映射。)clojure.lang.PersistentTreeMap/create
是一个命名Java方法的符号;这些在Clojure不是一流的。您可以将其封装在一个函数中--#(clojure.lang.PersistentTreeMap/create%)
--这个函数可以作为一个值使用,但实际上您当前的解决方案在我看来更好。如果您想对clojure.lang.IPersistentMap
重新使用现有的打印方法实现,可以(1)使用(get(methods print method)clojure.lang.IPersistentMap)
(它只是一个函数),(2)将其存储在方便的地方,(3)从自己的print method实现中调用它。我将编辑我的答案以演示。
(deftest reader-literal-test
(testing "#sorted/map"
(is (= (sorted-map :v 4 :w 5 :x 6 :y 7 :z 8)
#sorted/map {:v 4 :w 5 :x 6 :y 7 :z 8}))))
(deftest str-test
(testing "str"
(is (= "#sorted/map {:v 4, :w 5, :x 6, :y 7, :z 8}"
(str (sorted-map :v 4 :w 5 :x 6 :y 7 :z 8))))))