繁体   English   中英

Clojure:如何合并具有相同值的地图向量

[英]Clojure: How to merge vector of maps that have the same value

将映射的一个向量的值添加到具有给定键的相同值的另一个映射的向量的值的惯用方式是什么,其中映射的键名不同。 IE浏览器。

(def v1 
[{:name "name1" :address "address1"} 
{:name "name2" :address "address2"}])

(def v2 
[{:title "name1" :datofBirth "1-1-1971"} 
{:title "name3" :dateOfBirth "2-1-1971"}]) 

合并结果应该是

res 
 [{:name "name1" :address "address1" :dateofBirth "1-1-1971"}
{:name "name2" :address "address2" :dateOfBirth nil}]

通话应该看起来像这样

 (join v1 v2 :name :title)

身体看起来应该像这样,也许应该使用assoc-in

 (assoc-in v1 [(map-where-the-values-are-the-same) :key2] (value-from-the-2nd-map))

对于内部联接,可以使用clojure.set/join

(clojure.set/join v1 v2 {:name :title})

您的样本结果似乎表明您想要执行左联接。 如果是这样,您可能需要研究Clojure中外部联接的一些现有Stack Overflow问题; 例如,我对Clojure问题中最近的完全外部联接的两个映射序列的回答为完全外部联接问题提供了一种有力的解决方案,可以直接将其应用于产生左联接。

这是一种可能的改编:

(defn left-join [key-map xs ys]
  (let [kes (seq key-map)
        lks (mapv key kes)
        rks (mapv val kes)
        gxs (group-by #(mapv (fn [k] (get % k)) lks) xs)
        gys (dissoc (group-by #(mapv (fn [v] (get % v)) rks) ys) nil)
        kvs (keys gxs)]
    (persistent!
     (reduce (fn [out kv]
               (let [l (get gxs kv)
                     r (get gys kv)]
                 (if (seq r)
                   (reduce (fn [out m1]
                             (reduce (fn [out m2]
                                       (conj! out (merge m1 m2)))
                                     out
                                     r))
                           out
                           l)
                   (reduce conj! out l))))
             (transient [])
             kvs))))

在REPL:

(left-join {:name :title} v1 v2)
;= [{:name "name1", :datofBirth "1-1-1971", :title "name1",
     :address "address1"}
    {:name "name2", :address "address2"}]

如果您希望从结果映射中dissoc :title并将缺少的键添加到左侧没有相应记录的记录中,则可以稍微修改该函数,或者只是在后处理步骤中进行操作。

最好先创建小函数,然后使用线程宏进行调用。 在下面找到代码。

 (def v1 [{:name "name1" :address "address1"} 
     {:name "name2" :address "address2"}
     {:name "name4" :address "address2"}])

  (def v2 [{:title "name1" :datofBirth "1-1-1971"} 

     {:title "name3" :dateOfBirth "2-1-1971"}
     {:title "name4" :dateOfBirth "2-1-1971"}
     ]) 

(defn filter [k1 k2]
  (fn [d1 d2]
    (for [m1 d1
          m2 d2 
      :let [n1 (k1 m1)
            t1 (k2 m2)]
      :when (= n1 t1) ]
    (merge m1 (dissoc m2 k2)))))


(defn data-join [k1]
  (fn [d1 d2]
    (reduce (fn [acc t] 
          (map (fn [v1 v2] 
                (if (= (k1 v1)
                       (k1 v2))
                  v1 v2)) (repeat t) acc))
        d1 d2)))

    (->> v2 
       ((filter :name :title) v1  )
       ((data-join :name) v1))

过滤功能从v2过滤数据。 然后与结果一起加入。 可以使两个功能都变小。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM