Return a set that is the intersection of the input sets
user=> (clojure.set/intersection #{1}) #{1} user=> (clojure.set/intersection #{1 2} #{2 3}) #{2} user=> (clojure.set/intersection #{1 2} #{2 3} #{3 4}) #{} user=> (clojure.set/intersection #{1 :a} #{:a 3} #{:a}) #{:a}
(defn find-divisors [x] (->> (range 1 (inc x)) (into #{} (filter #(zero? (mod x %)))))) (find-divisors 10) ;; => #{1 2 5 10} ;; Greatest common divisor (defn gcd [x y] (let [x-div (find-divisors x) y-div (find-divisors y)] (apply max (clojure.set/intersection y-div x-div)))) (gcd 10 5) ;; => 5 ;; Lowest common multiple (defn lcm [x y] (/ (Math/abs (* x y)) (gcd x y))) (lcm 13 11) ;; => 143
(clojure.set/intersection #{:a :b :c} #{:d :c :b}) ;=> #{:b :c} (clojure.set/intersection #{:a :e :i :o :u} #{:a :u :r} #{:r :u :s}) ;=> #{:u}
;; Advice: Do not call intersection with non-set arguments. If you ;; are concerned that you may be unintentionally doing so, and want an ;; exception to be thrown if you do, consider using the library ;; funjible (https://github.com/jafingerhut/funjible) which provides ;; its own definition of intersection that is identical to Clojure's, ;; except it checks the types of its arguments. ;; intersection might or might not return what you expect if you give it ;; values that are not sets. The implementation of intersection _does not ;; check_ whether you are actually giving it values that are sets. It ;; _assumes_ so. ;; It is possible that intersection _might_ throw an exception if you ;; give it a non-set as an argument: user=> (intersection #{1 3 5} [2 4]) ClassCastException clojure.lang.PersistentVector cannot be cast to clojure.lang.IPersistentSet clojure.core/disj (core.clj:1517) ;; But it can also simply return an answer that is not the ;; intersection of the two collections: user=> (intersection #{1 3 5} [2 4 6 8]) #{1 3} ;; In the previous case, it includes elements in the returned set that ;; you would not expect. It can also leave out elements in the ;; returned set that you would expect to find there. user=> (intersection #{"1" "3" "5"} ["1" "3" "5" "7"]) #{} ;; Why not change the definition of intersection so it always throws ;; an exception if you give it a non-set argument? I would guess that ;; the primary reason is that the extra run-time type checks would ;; slow intersection down by an amount that the Clojure core team does ;; not want everyone to have to pay on every such call. ;; Related Clojure tickets: ;; https://dev.clojure.org/jira/browse/CLJ-1953 ;; https://dev.clojure.org/jira/browse/CLJ-2287
;; using clojure.set operations as query optimization: ;; given a vector of map items: (def data [{:gender "male", :age-group "child", :origin "Germany", :prename "Hans"} {:gender "male", :age-group "adult", :origin "France", :prename "Jacques"} {:gender "male", :age-group "senior", :origin "Estonia", :prename "Rasmus"} {:gender "male", :age-group "adult", :origin "Poland", :prename "Jakub"} {:gender "male", :age-group "senior", :origin "Germany", :prename "Uwe"} {:gender "female", :age-group "adult", :origin "France", :prename "Amélie"} {:gender "female", :age-group "child", :origin "Estonia", :prename "Sofia"} {:gender "female", :age-group "child", :origin "Germany", :prename "Emma"} {:gender "female", :age-group "child", :origin "Estonia", :prename "Alisa"} {:gender "female", :age-group "senior", :origin "Poland", :prename "Anna"}]) ;; we can create key -> "value" -> set of idx pointers ;; note: (reduce-kv calls aggregator fn with [aggregate index-in-vector value] when using vectors as the key-value collection. (def db-index (reduce-kv (fn [db idx item] (reduce (fn [db index-on] (update db index-on update (get item index-on) (fnil conj #{}) idx)) db [:gender :age-group :origin :prename])) {} data)) ;; results in this key - val -> #{indexes} in vector {:gender {"male" #{0 1 4 3 2}, "female" #{7 6 9 5 8}}, :age-group {"child" #{0 7 6 8}, "adult" #{1 3 5}, "senior" #{4 2 9}}, :origin {"Germany" #{0 7 4}, "France" #{1 5}, "Estonia" #{6 2 8}, "Poland" #{3 9}}, :prename {"Sofia" #{6}, "Rasmus" #{2}, "Hans" #{0}, "Amélie" #{5}, "Jakub" #{3}, "Jacques" #{1}, "Emma" #{7}, "Alisa" #{8}, "Uwe" #{4}, "Anna" #{9}}} ;; by using intersection on two different key-values indexes we get the items ;; with these properties, for instance "find all men from Germany" (def all-men-from-germany-idxs (clojure.set/intersection (get-in db-index [:gender "male"]) (get-in db-index [:origin "Germany"]))) ;; (map data (sort all-men-from-germany-idxs))
Return a set that is the first set without elements of the remaining sets
intersection