如果集合2不包含集合1中的项目,则将集合1中的项目添加到集合2

时间:2014-12-21 00:57:09

标签: clojure

我有两张地图:

(def people {:1 "John" :2 "Paul" :3 "Ringo" :4 "George"})

(def band 
  {:data 
    {:members 
      {:1 {:id 1 :name "John"} 
       :2 {:id 2 :name "Paul"}}}})

我想循环遍历people并将[:data :members]中不存在的任何成员添加到band,从而导致:

(def band 
  {:data 
    {:members 
      {:1 {:id 1 :name "John"} 
       :2 {:id 2 :name "Paul"}
       :3 {:id 3 :name "Ringo"}
       :4 {:id 4 :name "George"}}}})

这是我尝试过的:

(for [[id name] people]
  (when-not
    (contains? (get-in band [:data :members]) id)
    (assoc-in band [:data :members id] {:id id :name name})))

哪个收益率:

({:data 
   {:members 
     {:4 {:id :4, :name "George"}, 
      :1 {:name "John", :id 1}, 
      :2 {:name "Paul", :id 2}}}} 
 nil 
 nil 
 {:data 
   {:members 
     {:1 {:name "John", :id 1}, 
      :2 {:name "Paul", :id 2}, 
      :3 {:id :3, :name "Ringo"}}}})

我不知道为什么我要找回band的每个变异列表。我在这做错了什么?如何将people中缺少的成员添加到band [:data :members]

1 个答案:

答案 0 :(得分:3)

要迂腐,你不能回复任何变异的乐队。实际上,Clojure最重要的特性之一是标准类型是不可移植的,主要的集合操作返回修改后的副本而不改变原始类型。

此外,Clojure中的for不是循环,它是列表理解。这就是为什么它总是返回每个步骤的序列。因此,不是一次一步地改变输入,而是为每个步骤的输入创建了一个新的变体,每个变量都来自不可变原始。

基于值序列制作输入的一系列更新副本的标准构造是reduce,它将累加器的新版本和列表的每个元素传递给您的函数。

最后,你误解了:keyword语法的作用 - 为了构造地图键,不需要为项添加前缀:几乎任何clojure值都是地图的有效键,关键字是只是一个方便的习语。

user=> (def band 
            {:data 
              {:members 
                {1 {:id 1 :name "John"} 
                 2 {:id 2 :name "Paul"}}}})
#'user/band
user=> (def people {1 "John" 2 "Paul" 3 "Ringo" 4 "George"})
#'user/people
user=>  (pprint
         (reduce (fn [band [id name :as person]]
                    (if-not (contains? (get-in band [:data :members]) id)
                      (assoc-in band [:data :members id] {:id id :name name})
                      band))
                  band
                  people))
{:data
 {:members
  {3 {:id 3, :name "Ringo"},
   4 {:id 4, :name "George"},
   1 {:name "John", :id 1},
   2 {:name "Paul", :id 2}}}}
nil

您可能会注意到传递给fn的{​​{1}}的正文与您reduce理解的正文基本相同。不同之处在于,我使用for代替when-not,而if-not使用band,这允许我们传播累加器(此处称为{{1}},与输入相同),而不管是否有任何新版本。