Сериализация отсортированных карт в Clojure / 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. Временами это кажется удобным, а в других - неудобным.
- EDN не имеет поддержки отсортированных карт.
- Clojure поддерживает собственные литералы с тегами для читателя.
Дополнительные ресурсы:
2 ответа
Тот же вопрос с двумя полезными ответами: Сохранение + чтение отсортированных карт в файл в 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
"s 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))
С этим на месте:
user=> (sorted-map :foo 1 :bar 2)
#sorted/map {:bar 2, :foo 1}
В 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)
потерял бы порядок и таким образом запутал бы печать, но это работает в моем тестировании. Я не знаю почему.