簡體   English   中英

Clojure宏將保存關聯映射順序

[英]Clojure macro that will conserve associative map order

作為前言,我在Windows 7(64位)上運行Java版本6(更新33),使用clooj作為我的IDE。 我沒有嘗試在任何其他系統中重現我的問題。 我對Clojure很有經驗,但對Java一點也不熟悉。

我試圖解決的問題的全部內容很難描述,但它歸結為:我想說我想制作一個帶有一個參數的宏,一個關聯映射,並返回一個元素的向量地圖與他們的訂單保存。

=>(defmacro vectorize-a-map
    [associative-map]
    (vec associative-map))
=>#'ns/vectorize-a-map
=>(vectorize-a-map {:a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 7 :h 8}
=>[[:a 1] [:b 2] [:c 3] [:d 4] [:e 5] [:f 6] [:g 7] [:h 8]]

這是有效的,但添加另一個元素到地圖和訂單搞砸...

=>(vectorize-a-map {:a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 7 :h 8 :i 9}
=>[[:a 1] [:c 3] [:b 2] [:f 6] [:g 7] [:d 4] [:e 5] [:i 9] [:h 8]]

我相信我已經發現了為什么會這樣。 似乎任何具有8個或更少元素的東西都被實例化為PersistentArrayMap,這正是我想要的,因為據我所知,這個類保留了順序。 但是,具有9個或更多元素的任何內容都將實例化為PersistentHashMap,而不會保留順序。

=>(type {:a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 7 :h 8}
=>clojure.lang.PersistentArrayMap
=>(type {:a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 7 :h 8 :i 9}
=>clojure.lang.PersistentHashMap

我希望我的宏能夠獲取任何大小的關聯映射,所以這是一個問題。 我曾嘗試類型提示,解構綁定列表理解,和所享有的拼接,都沒有成功。 要繪制出來,以下任何一個都不會起作用:

(defmacro vectorize-a-map
  [^clojure.lang.PersistentArrayMap associative-map]
  (vec associative-map))

(defmacro vectorize-a-map
  [[& associative-map]]
  (vec associative-map))

(defmacro vectorize-a-map
  [associative-map]
  (vec
    (for [x associative-map]
      x)))

(defmacro vectorize-a-map
  [associative-map]
  `(vector ~@associative-map))

由於我提出這個玩具問題,我意識到我可以簡單地編寫我的宏,並完全避免這個問題:

=>(defmacro vectorize-kvs
    [& elements]
    (vec (map vec (partition 2 elements))))
=>#'ns/vectorize-kvs
=>(vectorize-kvs :a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 7 :h 8 :i 9)
=>[[:a 1] [:b 2] [:c 3] [:d 4] [:e 5] [:f 6] [:g 7] [:h 8] [:i 9]]

但是,對於我試圖解決的實際問題(我還沒有進入),重要的是(雖然不是100%必要)宏可以采用關聯映射。 看起來我正在尋找如何在任何事情發生之前將參數轉換為PersistentArrayMap。 我可能還有其他一些解決方案,我根本就沒有考慮或意識到這一點。

我已經研究了我所知道的最好的,但還沒有發現任何有用的東西。 有沒有人有任何想法/建議?

你可以使用array-map制作你的地圖

user> (map vec (array-map 1 2 3 4 5 6))
([1 2] [3 4] [5 6])

或者使用更大的地圖

user> (map vec (apply array-map (range 50)))
([0 1] [2 3] [4 5] [6 7] [8 9] [10 11] [12 13] [14 15] [16 17] [18 19] [20 21] [22 23] [24 25] [26 27] [28 29] [30 31] [32 33] [34 35] [36 37] [38 39] [40 41] [42 43] [44 45] [46 47] [48 49])

作為獎勵你可以避免使用宏,這是有用的,因為宏不是一流的,不能很好地組成*


關於陣列圖上文檔的第一條評論的注釋

  請注意,數組映射僅在未經修改時保持排序順序。 \n  后續關聯最終將使其“成為”哈希映射。 

如果您發現自己取決於地圖中按鍵的順序,您可能需要考慮一個sorted-map是否能滿足您的需求。 它比array-map更好地擴展。 在上面的例子中,輸出是相同的:

 (map vec (apply sorted-map (range 5000))) [0 1] [2 3] ... [4998 4999] 

*這是我的意見


編輯:

sorted-maparray-map的時間比較

 user> (time (dorun (map vec (apply sorted-map (range 500000))))) "Elapsed time: 391.520491 msecs" nil user> (time (dorun (map vec (apply array-map (range 500000))))) "Elapsed time: 674517.821669 msecs" 

所述問題不可解決。 地圖被定義為沒有訂單; 你在array-map看到的任何順序都是巧合。 如果您要求宏接收地圖,則您已經丟失了所需的信息。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM