我引用了一个添加了地图的vector []。 如果我想根据谓词匹配更改地图项的值,那么这样做的惯用方法是什么?
例如......
[ {:id 1:名称“Joe”} {:id 2:名称“Fred”} ]
我们希望将任何ID为2更新为“Brian”。
答案 0 :(得分:6)
这是一种方式:
(def people [ { :id 1 :name "Joe" } { :id 2 :name "Fred" } ])
(defn brian-converter [person]
(if (= 2 (:id person))
(assoc person :name "Brian")
person))
(map brian-converter people)
;;=> ({:id 1, :name "Joe"} {:id 2, :name "Brian"})
根据您对这些值的预期变化,您可能更喜欢更灵活的内容:
(defn create-converter [[key-to-match val-to-match]
key-to-replace val-to-replace]
(fn [person]
(if (= val-to-match (key-to-match person))
(assoc person key-to-replace val-to-replace)
person)))
(map (create-converter [:id 2] :name "Brian") people)
;;=> ({:id 1, :name "Joe"} {:id 2, :name "Brian"})
(map (create-converter [:id 1] :name "Dude") people)
;;=> ({:id 1, :name "Dude"} {:id 2, :name "Fred"})
在create-converter
中选择参数表示(搜索参数的向量,替换的展开参数)对我来说是任意的;不确定是否有规则。
答案 1 :(得分:4)
另一种方法是找到要更新的地图的索引,然后只更新该地图[编辑:假设您只想更新矢量中的单个项目]:
(def people [{:id 1 :name "Joe"} {:id 2 :name "Fred"}])
(defn vecmap-assoc-pred
[vm pred & kvs]
(let [i (some (fn [[i m]] (when (pred m) i))
(map-indexed vector vm))]
(apply update-in vm [i] assoc kvs)))
(vecmap-assoc-pred people #(= 2 (:id %)) :name "Brian")
对于这种特殊情况,使用由id:
键入的人物地图可能更有意义(def people {1 {:id 1 :name "Joe"} 2 {:id 2 :name "Fred"}})
(assoc-in people [2 :name] "Brian")