1.3.0 permalink Arrow_down_16x16
  • (join xrel yrel)
  • (join xrel yrel km)
When passed 2 rels, returns the rel corresponding to the natural
join. When passed an additional keymap, joins on the corresponding
keys.

1 Example top

  • ;; This simple example shows each element of the first relation joined
    ;; with each element of the second (because they have no columns in common):
    
    user=> (def first-relation #{ {:a 1} {:a 2} })
    user=> (def second-relation #{ {:b 1} {:b 2} })
    user=> (join first-relation second-relation)
    #{{:b 1, :a 1} 
      {:b 2, :a 1} 
      {:b 1, :a 2} 
      {:b 2, :a 2}}
    
    
    ;; Here's a larger example, in which a relation mainly about animal ownership
    ;; is joined with a relation about animal personality. The join is used to 
    ;; produce a relation joining information about an animal's personality to 
    ;; that animal.
    
    user=> (def animals #{{:name "betsy" :owner "brian" :kind "cow"}
                          {:name "jake"  :owner "brian" :kind "horse"}
                          {:name "josie" :owner "dawn"  :kind "cow"}})
    
    user=> (def personalities #{{:kind "cow" :personality "stoic"}
                                {:kind "horse" :personality "skittish"}})
    #'user/personalities
    user=> (join animals personalities)
    
    #{{:owner "dawn",  :name "josie", :kind "cow",   :personality "stoic"}
      {:owner "brian", :name "betsy", :kind "cow",   :personality "stoic"}
      {:owner "brian", :name "jake",  :kind "horse", :personality "skittish"}}
    
    
    ;; (If cows had two personalities, instead of one, each cow would have 
    ;; two rows in the output.)
    
    ;; Suppose `personalities` used `:species` instead of `:kind`:
    
    user=>  (def personalities #{{:species "cow" :personality "stoic"}
                                 {:species "horse" :personality "skittish"}})
    
    
    ;; A simple join would produce results like this:
    
    user=> (join animals personalities)
    #{{:kind "horse", :owner "brian", :name "jake", :species "cow", :personality "stoic"}
      {:kind "cow", :owner "dawn", :name "josie", :species "cow", :personality "stoic"}
      {:kind "horse", :owner "brian", :name "jake", :species "horse", :personality "skittish"}
      {:kind "cow", :owner "brian", :name "betsy", :species "cow", :personality "stoic"}
      {:kind "cow", :owner "dawn", :name "josie", :species "horse", :personality "skittish"}
      {:kind "cow", :owner "brian", :name "betsy", :species "horse", :personality "skittish"}}
    
    
    ;; Notice that "Jake" is both a horse and a cow in the first line. That's 
    ;; likely not what you want. You can tell `join` to only produce output 
    ;; where the `:kind` value is the same as the `:species` value like this:
    
    user=> (join animals personalities {:kind :species})
    #{{:kind "cow", :owner "dawn", :name "josie", :species "cow", :personality "stoic"}
      {:kind "horse", :owner "brian", :name "jake", :species "horse", :personality "skittish"}
      {:kind "cow", :owner "brian", :name "betsy", :species "cow", :personality "stoic"}}
    
    
    ;; Notice that the `:kind` and `:species` keys both appear in each output map.
    
    
Log in to add / edit an example.

See Also top

Log in to add a see also.

Plus_12x12 Minus_12x12 Source clojure/set.clj:111 top

(defn join
  "When passed 2 rels, returns the rel corresponding to the natural
  join. When passed an additional keymap, joins on the corresponding
  keys."
  {:added "1.0"}
  ([xrel yrel] ;natural join
   (if (and (seq xrel) (seq yrel))
     (let [ks (intersection (set (keys (first xrel))) (set (keys (first yrel))))
           [r s] (if (<= (count xrel) (count yrel))
                   [xrel yrel]
                   [yrel xrel])
           idx (index r ks)]
       (reduce (fn [ret x]
                 (let [found (idx (select-keys x ks))]
                   (if found
                     (reduce #(conj %1 (merge %2 x)) ret found)
                     ret)))
               #{} s))
     #{}))
  ([xrel yrel km] ;arbitrary key mapping
   (let [[r s k] (if (<= (count xrel) (count yrel))
                   [xrel yrel (map-invert km)]
                   [yrel xrel km])
         idx (index r (vals k))]
     (reduce (fn [ret x]
               (let [found (idx (rename-keys (select-keys x (keys k)) k))]
                 (if found
                   (reduce #(conj %1 (merge %2 x)) ret found)
                   ret)))
             #{} s))))
Vars in clojure.set/join:
Used in 0 other vars

Comments top

No comments for join. Log in to add a comment.