2013-06-27 26 views
4

我通過spit將嵌套的數據映射保存到磁盤。我希望我的地圖中的一些地圖可以排序,並且當我將地圖重新​​放入我的程序時保持排序。排序後的地圖沒有唯一的文字表示形式,因此當我將spit地圖映射到磁盤上時,排序後的地圖和未排序的地圖表示相同,並且數據會使每個地圖成爲通常的未排序類型。這裏有一個例子玩具能說明問題:將已排序的地圖保存到Clojure的文件中

(def sorted-thing (sorted-map :c 3 :e 5 :a 1)) 
;= #'user/sorted-thing 
(spit "disk" sorted-thing) 
;= nil 
(def read-thing (read-string (slurp "disk"))) 
;= #'user/read-thing 

(assoc sorted-thing :b 2) 
;= {:a 1, :b 2, :c 3, :e 5} 
(assoc read-thing :b 2) 
;= {:b 2, :a 1, :c 3, :e 5} 

是否有某種方式來讀取作爲排序的地圖擺在首位,而不是看完後把它們轉換成排序的地圖?或者這是一個跡象表明我應該使用某種真實的數據庫?

+2

查看帶有標籤元素的[EDN](https://github.com/edn-format/edn)。 –

+0

如果你把它寫成JSON,並將其讀回到'sorted-map'中,是否滿足你的要求? – Kevin

+0

@Kevin如何告訴'clojure.data.json'如何讀取as中的對象?或者你的意思是不同的圖書館? – num1

回答

4

*print-dup*動態rebindable無功的目的是支持這種使用情況:

(binding [*print-dup* true] 
    (prn (sorted-map :foo 1))) 
; #=(clojure.lang.PersistentTreeMap/create {:foo 1}) 

註釋掉行是什麼變打印。

恰巧當應用於Clojure的數據結構,因此也spit,這也影響str,所以如果你做

(binding [*print-dup* true] 
    (spit "foo.txt" (sorted-map :foo 1))) 

寫入foo.txt地圖表示將上面顯示的一個。

無可否認,我並不是100%確定這是否記錄在某個地方;如果你感到不安這一點,你總是可以spit使用pr-str*print-dup*勢必true結果:

(binding [*print-dup* true] 
    (pr-str (sorted-map :foo 1))) 
;= "#=(clojure.lang.PersistentTreeMap/create {:foo 1})" 

(此時間的最後一行是返回,而不是打印輸出的值。)

顯然您必須將*read-eval*綁定到true才能夠回讀這些文字。這很好,但它的目的正是爲了服務(從可信來源讀取代碼)。

+0

你永遠不會驚訝我。很好的答案。 – dbyrne

+1

這可能是最好的方法,但它並不完美:它總是使用默認的地圖比較器,所以如果你有一個按其他東西排序的有序地圖,那麼你讀回的地圖將不匹配。關於這一點你可以做的不多,只是寫了一個類似'#sorted/map [(fn [...]){:foo 1}]''的'自定義序列化程序和一個相應的數據讀取器。當然,那麼你必須確保比較器功能也可以被序列化。 – amalloy

4

我不認爲它一定是你應該使用數據庫的標誌,但我認爲它是一個標誌,你不應該使用spit。將有序映射寫入磁盤時,請勿使用映射文字語法。如果你寫出來的格式如下,讀字符串將工作:

(def sorted-thing (eval (read-string "(sorted-map :c 3 :e 5 :a 1)"))) 
(assoc sorted-thing :b 2) 
;= {:a 1, :b 2, :c 3, :e 5} 
+0

這就是我所要求的,我會在將來注意到它。雖然,每次我想保存聲音時,將每個排序映射(可能有數百個)的所有條目(可能有數千個)放到調用'sorted-map'的位置,可能會變慢。我真的應該尋找某種數據庫...... – James

+1

@詹姆斯,你覺得'clojure.core/pr-str'現在在做什麼?它將每個映射中的所有條目都放在'\ {\}'字符中。自己做這件事的代價不會破壞你。 – amalloy

+0

只需通過'pr-str'就可以了,你說得對。謝謝你指出。 – James

相關問題