在Clojure / EDN中序列化已排序的地图?

时间:2013-08-08 05:09:28

标签: 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}

我注意到了什么:

  1. 有序地图的显示方式与REPL中未分类的地图的显示方式相同。这似乎很方便,但在其他方面不方便。
  2. EDN不支持sorted maps
  3. Clojure支持custom tagged literals for the reader
  4. 其他资源:

2 个答案:

答案 0 :(得分:1)

同样的问题有两个可用的答案:Saving+reading sorted maps to a file in Clojure

第三个答案是设置自定义阅读器文字。您可以将排序后的地图打印为

;; 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的{​​{1}} impl:

print-method

有了这个:

(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))

答案 1 :(得分:0)

data_readers.clj

{sorted/map my-app.core/create-sorted-map}

注意:我希望这可行,但它没有(不确定原因):

{sorted/map clojure.lang.PersistentTreeMap/create}

现在,在my-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))))))

这很大程度上取决于我在上面找到的资源。

注意:我很惊讶print-method在上面工作。在我看来,(into {} o)会失去排序,从而打乱了打印,但它在我的测试中起作用。我不知道为什么。