开发者

NOT - EXISTS / NOT - IN type query in Clojure

开发者 https://www.devze.com 2023-04-02 08:06 出处:网络
I have 2 data structure开发者_C百科slike the ones below (ns test) (def l [{:name \"Sean\" :age 27}

I have 2 data structure开发者_C百科s like the ones below

(ns test)

(def l 
  [{:name "Sean" :age 27} 
   {:name "Ross" :age 27}
   {:name "Brian" :age 22}])

(def r 
  [{:owner "Sean" :item "Beer" }
   {:owner "Sean" :item "Pizza"}
   {:owner "Ross" :item "Computer"} 
   {:owner "Matt" :item "Bike"}])

I want to have get persons who dont own any item . (Brian in this case so [ {:name "Brian" :age 22}] If this was SQL I would do left outer join or not exists but I not sure how to do this in clojure in more performant way.


While Chuck's solution is certainly the most sensible one, I find it interesting that it is possible to write a solution in terms of relational algebraic operators using clojure.set:

(require '[clojure.set :as set])
(set/difference (set l)
                (set/project (set/join r l {:owner :name})
                             #{:name :age}))
; => #{{:name "Brian", :age 22}}


You basically want to do a filter on l, but negative. We could just not the condition, but the remove function already does this for us. So something like:

(let [owner-names (set (map :owner r))]
  (remove #(owner-names (% :name)) l))

(I think it reads more nicely with the set, but if you want to avoid allocating the set, you can just do (remove (fn [person] (some #(= (% :owner) (person :name)) r)) l).)

0

精彩评论

暂无评论...
验证码 换一张
取 消