使用投影函数设置差异

时间:2013-10-22 17:26:48

标签: clojure

我有两个数据库,我试图使用一些Clojure胶水代码保持同步。

我想制作像clojure.set/difference这样的东西,它对函数投射的值进行操作。

以下是一些示例数据:

(diff #{{:name "bob smith" :favourite-colour "blue"} 
        {:name "geraldine smith" :age 29}}

      #{{:first-name "bob" :last-name "smith" :favourite-colour "blue"}} 

       :name 
       (fn [x] (str (:first-name x) " " (:last-name x))))

 ;; => {:name "geraldine smith" :age 29}

我得到的最好的是:

(defn diff
  "Return members of l who do not exist in r, based on applying function
   fl to left and fr to right"
  [l r fl fr]
  (let [l-project (into #{} (map fl l))
        r-project (into #{} (map fr r))
        d (set/difference l-project r-project)
        i (group-by fl l)]
     (map (comp first i) d)))

但我觉得这有点笨拙,我无法想象它表现得很好。我丢弃了我想保留的信息,然后再查看。

我确实使用了元数据,以便在设置差异期间保持原始值,但我似乎无法将元数据放在原始类型上,因此无效...

我不知道为什么,但是我脑子里有这么小的声音告诉我,这方面的操作是monad的用途,而且我应该真正开始找出什么是monad是以及如何使用它。关于微小的声音是否正确的任何指导都是非常受欢迎的!

1 个答案:

答案 0 :(得分:2)

(defn diff
  [l r fl fr]
  (let [r-project (into #{} (map fr r))]
    (set (remove #(contains? r-project (fl %)) l))))

这不再直接暴露差异操作(现在隐含了remove / contains组合),但它很简洁,应该给出你想要的结果。

示例用法和输出:

user> (diff #{{:name "bob smith" :favourite-colour "blue"} 
              {:name "geraldine smith" :age 29}}

            #{{:first-name "bob" :last-name "smith" :favourite-colour "blue"}} 

            :name 
            (fn [x] (str (:first-name x) " " (:last-name x))))

#{{:age 29, :name "geraldine smith"}}