2010-02-24 40 views
12

考慮:如何更新Clojure中的矢量項?

(def my-vec [{:id 0 :a "foo" :b "bar"} {:id 1 :a "baz" :b "spam"} 
      {:id 2 :a "qux" :b "fred"}]) 

我怎樣才能慣用更新*在我-VEC與:id=1的項目有價值觀:a="baz2":b="spam2"

*:我承認我實際上不會更新my-vec,但真的會返回一個與我的vec相同的新的向量,除了替換值。

回答

8

地圖上地圖的載體功能,要麼創建,如果密鑰匹配修改地圖或利用原有如果密鑰不匹配,那麼把結果返回到一個向量

(vec (map #(if (= (:id %) 1) 
      (assoc % :a "baz2" :b "spam2") 
      %))) 

它可以更簡潔地做到這一點,雖然這真的顯示結構共享發生的地方。

+0

使用#(%)函數語法是否使這個不太清楚? – 2010-02-25 19:30:05

10

您是否知道提前使用id == 1的地圖是您矢量中的第二張地圖?如果是這樣的:

user> (-> my-vec 
      (assoc-in [1 :a] "baz2") 
      (assoc-in [1 :b] "spam2")) 
[{:id 0, :a "foo", :b "bar"} {:id 1, :a "baz2", :b "spam2"} {:id 2, :a "qux", :b "fred"}] 

如果需要通過ID來訪問你的數據很多,另一個想法是哈希映射的哈希鍵地圖上:id更換您的哈希地圖矢量。那麼無論事物的順序如何,你都可以更容易地assoc-in

user> (def new-my-vec (zipmap (map :id my-vec) my-vec)) 
#'user/new-my-vec 
user> new-my-vec 
{2 {:id 2, :a "qux", :b "fred"}, 1 {:id 1, :a "baz", :b "spam"}, 0 {:id 0, :a "foo", :b "bar"}} 
user> (-> new-my-vec 
      (assoc-in [1 :a] "baz2") 
      (assoc-in [1 :b] "spam2")) 
{2 {:id 2, :a "qux", :b "fred"}, 1 {:id 1, :a "baz2", :b "spam2"}, 0 {:id 0, :a "foo", :b "bar"}} 
+0

嗯。我將它存儲在一個矢量中,因爲我實際上所持有的是紙牌的ImageIcons,當我繪製時,矢量位置將作爲z順序起作用。 [{:id「8H」:image ImageIcon} ...]。但是我可能能夠將它們存儲在地圖{{:id「8H」:z-order 2:image ImageIcon} ...}中,然後通過將它們按排序後的z順序拉出來進行Graphics.draw。謝謝,Brian,你是一個Clojure怪物。 :) – scrotty 2010-02-25 04:11:52

+4

'(update-in my-vec [1] assoc:a「baz2」:b「spam2」)'看起來要乾淨得多。 – amalloy 2011-04-02 07:49:41

3

可能要看一看array-map它創建一個由數組支持,並通過該指數,而不是使用鍵控圖:ID?