2013-08-08 1 views
2

어떻게 Clojure에서 정렬 된 맵을 직렬화 및 비 직렬화 할 수 있습니까? 예를 들어Clojure/EDN에서 정렬 된지도를 직렬화 하시겠습니까?

:

(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. EDNsorted maps을 지원하지 않습니다.
  3. Clojure는 custom tagged literals for the reader을 지원합니다.

추가 리소스 : 두 개의 가능한 답변

답변

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:reader 키를 포함 할 수도있는 opts지도 (선택 사항)를 허용합니다. 그 키의 값은 어떤 데이터 판독기가 어떤 태그에 사용할지를 지정하는 맵이됩니다. 자세한 내용은 (doc clojure.edn/read)을 참조하십시오.

인쇄의 경우 print-method에 대한 사용자 지정 방법을 설치하거나 정렬 된 맵 인쇄에 사용자 지정 함수를 사용할 수 있습니다. 아마 후자의 해결책을 생각해 볼 것입니다. 내장형 프로토콜/내장형을위한 다중 방법을 구현하는 것은 일반적으로 좋은 아이디어가 아니므로 특별한 경우에 합리적으로 보일지라도 특별한 치료가 필요합니다. 자신의 기능을 사용하는 것이 더 간단합니다.

업데이트 : 재사용하는 방법을 보여

IPersistentMapprint-method IMPL 깨끗하게 다윗의 대답에 코멘트에 약속 :

user=> (sorted-map :foo 1 :bar 2) 
#sorted/map {:bar 2, :foo 1} 
+0

NB. 'clojure.edn' 네임 스페이스가 Clojure 1.5에 도입되었습니다. –

0
: 장소에와

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

에서 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)) 

- 적은 낮은 -Level, 당신은 사용할 수 있습니다

(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)은 주문을 잃어 버리므로 인쇄를 중단하는 것처럼 보일 수 있지만 내 테스트에서는 작동합니다. 나는 이유를 모른다.

+1

테스트는 작기 때문에 기본적으로 "실수로"(Clojure의 구현 세부 사항) 테스트가 통과합니다. (작은지도'(into {} ...) '는 삽입 순서를 유지하는 배열 맵을 생성하기 때문에 테스트 크기가 중요합니다. 충분히 커지면 해시 맵으로 변환됩니다.) clojure.lang.PersistentTreeMap/create'는 Java 메소드를 명명하는 심볼입니다. 이들은 Clojure에서 일등급이 아닙니다. 값으로 사용할 수있는 것보다'# (clojure.lang.PersistentTreeMap/create %)'함수로 포장 할 수는 있지만 실제로 현재의 솔루션이 나에게 잘 어울립니다. –

+1

'clojure.lang.IPersistentMap'에 대한 기존의 print-method 구현을 조정할 때 재사용하려면 (1) (get (methods print-method) clojure.lang.IPersistentMap)' (그냥 함수 일뿐입니다.) (2) 편리하게 어딘가에 저장하고, (3) 자신의 print-method 구현에서 호출합니다. 시연을 위해 내 대답을 편집 할 것입니다. –

관련 문제