Join “是否有clojure函数?”;加入;两张地图清单?
我正在寻找一个与sql中的join类似的join函数,例如: 以下是两张地图列表:Join “是否有clojure函数?”;加入;两张地图清单?,join,clojure,Join,Clojure,我正在寻找一个与sql中的join类似的join函数,例如: 以下是两张地图列表: (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"}]) 我希望在用户id上加入a和b以获得: [{:user_id 1 :name "user 1" :email "e 1"}
(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"}])
我希望在用户id上加入a和b以获得:
[{:user_id 1 :name "user 1" :email "e 1"}
{:user_id 2 :name "user 2" :email "e 2"}]
clojure或其他库中是否有一些函数可以实现这一点?我认为没有任何简单的函数可以实现这一点,但我可能错了 如果您知道每个序列中都存在每个
user\u id
,则只需对user\u id
进行排序,然后将合并应用于相应的映射:
(defn sort-by-user-id
[m]
(sort #(< (:user_id %1) (:user_id %2)) m))
(map merge (sort-by-user-id a) (sort-by-user-id b))
; => ({:email "e 1", :name "user 1", :user_id 1} {:email "e 2", :name "user 2", :user_id 2})
然后像这样合并各个贴图,在过程结束时剥离关键点:
(vals (merge-with merge az bz))
; => ({:email "e 2", :name "user 2", :user_id 2} {:email "e 1", :name "user 1", :user_id 1})
总而言之:
(defn map-of-maps
[cm]
(zipmap (map :user_id cm) cm))
(defn merge-maps
[& cms]
(vals
(apply merge-with merge
(map map-of-maps cms))))
让我们确保它与缺少的用户id
s一起工作:
(def a+ (conj a {:name "user 3", :user_id 3}))
(def b+ (conj b {:email "e 4", :user_id 4}))
(merge-maps a+ b+)
; => ({:email "e 4", :user_id 4} {:name "user 3", :user_id 3} {:email "e 2", :name "user 2", :user_id 2} {:email "e 1", :name "user 1", :user_id 1})
如果有更简单或更优雅的方法,我不会感到惊讶。这只是我想到的一个策略。另一个选择,我觉得简单一点:
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})
groupby
创建从:user\u id
到包含给定值的所有映射的映射,vals
仅获取值(每个值都是一个向量),最后对于每个值向量,它们被合并。将完成此操作
(use 'clojure.set)
(clojure.set/join a b) ; => #{{:email "e 1", :name "user 1", :user_id 1} {:email "e 2", :name "user 2", :user_id 2}}
在不提供第三个参数的情况下,函数将在所有公用键上联接:
(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
(clojure.set/join a b) ; #{{:name "n 1", :url "u 1", :id1 1, :id2 2}}
(clojure.set/join a c) ; #{{:name "n 2", :url "u 2", :id1 2, :id2 3} {:name "n 1", :url "u 1", :id1 1, :id2 2}}
要仅在id1上加入a和b,请执行以下操作:
(clojure.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}}
我们甚至可以通过来自不同集合的不同键进行连接:
(clojure.set/join a b {:id1 :id2}) ; #{{:name "n 2", :url "u 1", :id1 1, :id2 2}}
在我发布我的答案后,我注意到了。我不确定这个问题是否完全相同;不清楚询问的是什么,因为示例覆盖了一个键的值(
:b
,在包含:a
的2
的映射中)。然而,这个问题的答案就是你问题的答案。所以我想这算是一个重复的问题。因为我的答案不同,所以我把它放在这里了,但也许我应该把它贴到另一个问题上?不确定。谢谢!我发现clojure.set/join可以做到这一点。查找“set”的函数并不明显。clojure.set/join可以获得两个集合的Cartision乘积,还可以接受关键字对来连接它们。(into{}(clojure.set/join a b))
返回映射。
(clojure.set/join a b {:id1 :id2}) ; #{{:name "n 2", :url "u 1", :id1 1, :id2 2}}