【问题标题】:Intersection of two hash-maps using clojure使用 clojure 的两个哈希映射的交集
【发布时间】:2018-03-13 09:49:29
【问题描述】:

我是 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))))))

这是我的 repl 结果:

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}

这可能看起来很复杂,我也在等待任何伟大而有效的解决方案。

非常感谢!

【问题讨论】:

    标签: clojure


    【解决方案1】:

    这可以通过merge-with 使用max 作为合并函数来完成:

    (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}
    

    要仅包含出现在两个映射中的键,您可以使用 select-keys 与两个映射键的集合交集:

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

    【讨论】:

    • 感谢您用解释说明解决方案!我认为有很多我不知道的内置功能需要进一步研究。有什么好的学习资源推荐吗?再次感谢!
    • Kamikid:解决4clojure练习,你会发现很多新功能。另请查看 Clojure 备忘单。
    • @Kamikid Michiel 所说的,加上 1) 略读 clojure.core API docs 有助于提供广泛的意义,2) 在 clojuredocs.org 上查找有趣的函数,并且在每个页面的底部都有 相关的函数,这是发现有用内容的另一种方式。
    【解决方案2】:
    (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}
    

    【讨论】:

    • 感谢 Michiel 实施您的解决方案。在用函数塑造集合时,merge-with 似乎非常方便和有用。
    【解决方案3】:

    你也可以像这样一次性完成:

    (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}
    

    【讨论】:

    • 感谢您提供解决问题的新方法。这个逻辑对我来说很简单,解决方案也很花哨!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多