Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a clojure function to "join" two list of maps?

Tags:

join

clojure

I am looking for a join function which is like join in sql,for example:

Here is two list of maps:

(def a [{:user_id 1 :name "user 1"} 
        {:user_id 2 :name "user 2"}])

(def b [{:user_id 2 :email "e 2"} 
        {:user_id 1 :email "e 1"}])

I want join a and b on user_id to get:

[{:user_id 1 :name "user 1" :email "e 1"} 
 {:user_id 2 :name "user 2" :email "e 2"}]

Is there some function in clojure or other library which could achieve this?

like image 204
user2219372 Avatar asked Dec 06 '22 23:12

user2219372


2 Answers

clojure.set/join will do the thing.

(require '[clojure.set :as set])

(set/join a b) ; => #{{:email "e 1", :name "user 1", :user_id 1} {:email "e 2", :name "user 2", :user_id 2}}

Without providing 3rd argument, function will join on all common keys:

(def a [{:id1 1 :id2 2 :name "n 1"} {:id1 2 :id2 3 :name "n 2"}])
(def b [{:id1 1 :id2 2 :url "u 1"} {:id1 2 :id2 4 :url "u 2"}])
(def c [{:id1 1 :id2 2 :url "u 1"} {:id1 2 :url "u 2"}]) ; :id2 is missing in 2nd record

(set/join a b) ; #{{:name "n 1", :url "u 1", :id1 1, :id2 2}}
(set/join a c) ; #{{:name "n 2", :url "u 2", :id1 2, :id2 3} {:name "n 1", :url "u 1", :id1 1, :id2 2}}

To join a and b only on id1:

(set/join a b {:id1 :id1}) ; #{{:name "n 2", :url "u 2", :id1 2, :id2 4} {:name "n 1", :url "u 1", :id1 1, :id2 2}}

We can even join by different keys from different collections:

(set/join a b {:id1 :id2}) ; #{{:name "n 2", :url "u 1", :id1 1, :id2 2}}
like image 57
Jarlax Avatar answered Dec 08 '22 12:12

Jarlax


Another option, a bit simpler I think:

user=> (map #(apply merge %) (vals (group-by :user_id (concat a b))))
({:email "e 1", :name "user 1", :user_id 1} {:email "e 2", :name "user 2", :user_id 2})

group-by creates a mapping from :user_id to all the maps containing a given value, vals gets only the values (each one a vector), and finally for each vector of values, they are merged.

like image 41
noisesmith Avatar answered Dec 08 '22 13:12

noisesmith