Clojure嵌套映射 - 修改值

17

我必须说,我大约两周前开始学习Clojure,并且现在已经被一个问题困扰了整整三天。

我得到的地图是这样的:

{
  :agent1 {:name "Doe" :firstname "John" :state "a" :time "VZ" :team "X"}
  :agent2 {:name "Don" :firstname "Silver" :state "a" :time "VZ" :team "X"}
  :agent3 {:name "Kim" :firstname "Test" :state "B" :time "ZZ" :team "G"}
}

我需要更改:team "X":team "H"

我尝试了很多东西,如assocupdate-in等,但都没有成功。

我该怎么做呢?非常感谢!

2个回答

20

assoc-in用于替换或插入指定路径的地图中的值

(def m { :agent1 {:name "Doe" :firstname "John" :state "a" :time "VZ" :team "X"}
         :agent2 {:name "Don" :firstname "Silver" :state "a" :time "VZ" :team "X"}
         :agent3 {:name "Kim" :firstname "Test" :state "B" :time "ZZ" :team "G"}})

(assoc-in m [:agent1 :team] "H")

{:agent1 {:state "a", :team "H", :name "Doe", :firstname "John", :time "VZ"},
 :agent2 {:state "a", :team "X", :name "Don", :firstname "Silver", :time "VZ"},
 :agent3 {:state "B", :team "G", :name "Kim", :firstname "Test", :time "ZZ"}}

然而,如果您想更新所有团队 "X",而不管具体路径,跨树的递归级别,您可以使用clojure.walk的prewalk或postwalk函数结合自己的函数:

(use 'clojure.walk)
(defn postwalk-mapentry
    [smap nmap form]
    (postwalk (fn [x] (if (= smap x) nmap x)) form))

(postwalk-mapentry [:team "X"] [:team "T"] m)

{:agent1 {:state "a", :team "T", :name "Doe", :firstname "John", :time "VZ"},
 :agent2 {:state "a", :team "T", :name "Don", :firstname "Silver", :time "VZ"},
 :agent3 {:state "B", :team "G", :name "Kim", :firstname "Test", :time "ZZ"}}

12

遍历函数对于替换操作非常有用。

(clojure.walk/prewalk-replace {[:team "X"] [:team "H"]} map)

通过传入向量,您可以确保不仅替换所有的 "X"。


很酷,我不知道你也可以使用 post- 和 prewalk-replace 更改键值组合!我以为它只适用于键。 - NielsK
它适用于整个结构 - 而且映射键值对在大多数情况下等同于[key value]向量(例如,考虑使用(into {} (map (fn [[k v]] [k (inc v)]) {:a 1 :b 2}))))。如果某物是等效的,它将替换它 - 无论它有多大。还要记住,您可以安全地使用任何Clojure数据结构作为映射中的键,这可能非常强大。 - deterb
你好,非常感谢您的回答!不幸的是,我了解到我只能使用核心函数,因为我们无法确保集成此代码的程序在其下一个版本中支持更多的函数。这个问题有解决的办法吗? - m-arv
你怎么能不保证呢?这是主要的Clojure库的一部分,我不认为命名空间会从中消失。clojure.walk覆盖了处理这种情况的最简单方法,在我找到它之前,我正在编写等效的代码。如果担心它不可用,当这种担忧实现时,我将使用在那里执行树遍历的策略 - 对于您的映射的主要结构将类似于(fn [f] (into {} (map (fn [[k v]] (if-let [result (transform k v)] result [k (f v)])(请注意,这未经测试) - deterb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接