使用clojure的两个哈希映射的交集

时间:2018-03-13 09:49:30

标签: clojure

我是Clojure的新手。我的问题是如何获得两个哈希映射的交集,例如

(def map-1 {"a" 2, "b" 1, "c" 4, "d" 3})
(def map-2 {"a" 3, "b" 6, "e" 5})

在我们定义两张地图时,预期结果为{"a" 3, "b" 6},它位于具有相交键和地图的最大值的地图中。

不知怎的,我想出了一个解决方案并实现了它,但它的工作原理部分正确。

基本思想是找到其中项目数量最少的地图,将其用作参考。对于参考地图中的每个项目,检查其他地图是否包含它。如果包含,则将键放在输出映射中,并使用其最大值(使用(max num1 num2)

以下是我的示例代码:

(defn max-intersect [map1 map2]
  (let [smaller-map (if (< (count map1) (count map2))
                      map1
                      map2)
        longer-map (if (= smaller-map map1)
                     map2
                     map1)]
        (loop [output {}
               reference-map smaller-map]
          (if (empty? reference-map)
            output
            (recur (let [[item-key item-val] (first smaller-map)]
                     (when (contains? longer-map item-key)
                       (assoc output item-key (max item-val (get longer-map item-key)))))
                   (rest reference-map))))))

这是我的复制结果:

test-intersect.core=> (def map1 {"a" 2, "b" 1, "c" 4, "d" 3})
#'test-intersect.core/map1
test-intersect.core=> (def map2 {"a" 3, "b" 6, "e" 5})
#'test-intersect.core/map2
test-intersect.core=> (max-intersect map1 map2)
{"a" 3}

看起来很复杂,我也在等待任何有效的解决方案。

非常感谢!

3 个答案:

答案 0 :(得分:8)

使用max作为合并功能{/ 3}}即可完成此操作:

(def map-1 {"a" 2, "b" 1, "c" 4, "d" 3})
(def map-2 {"a" 3, "b" 6, "e" 5})
(merge-with max map-1 map-2)
=> {"a" 3, "b" 6, "c" 4, "d" 3, "e" 5}

merge-withmerge类似,但它允许您传递一个函数,以便在两个地图中都显示某个键时选择合并后的值。

要仅包含两个地图中显示的关键字,您可以将select-keys与两个地图关键字的设置交集使用:

(select-keys (merge-with max map-1 map-2)
             (clojure.set/intersection
               (set (keys map-1))
               (set (keys map-2))))

答案 1 :(得分:1)

(require '[clojure.set :refer [intersection]])

(defn merge-with-max-intersecting
  [m1 m2]
  (let [intersecting (intersection (set (keys m1))
                                   (set (keys m2)))]
    (merge-with max
                (select-keys m1 intersecting)
                (select-keys m2 intersecting))))

(merge-with-max-intersecting {"a" 2, "b" 1, "c" 4, "d" 3}
                             {"a" 3, "b" 6, "e" 5})
;;=> {"a" 3, "b" 6}

答案 2 :(得分:1)

你也可以像这样一次通过:

(defn merge-maps [m1 m2]
  (reduce-kv (fn [acc k v]
               (if (contains? m1 k)
                 (assoc acc k (max v (m1 k)))
                 acc))
             {}
             m2))

user> (merge-maps map-1 map-2)
;;=> {"a" 3, "b" 6}