【问题标题】:Clojure Multi MapsClojure 多映射
【发布时间】:2012-06-12 03:28:24
【问题描述】:

非常简单+愚蠢的问题:

clojure 是否提供多地图?我目前有这样的事情:

(defn wrap [func]
  (fn [mp x]
    (let [k (func x)]
      (assoc mp k
             (match (get mp k)
               nil [x]
               v (cons v x))))))

(defn create-mm [func lst]
  (reduce (wrap func) {} lst))

最终创建了一个映射,其中对于每个键,我们都有一个包含该键的所有元素的向量。不过好像multi map是一个很基础的数据结构,不知道clojure有没有内置的。

谢谢

【问题讨论】:

    标签: clojure


    【解决方案1】:

    我认为这作为一个独特的类型并不是真正必要的,因为 Clojure 的灵活性允许您通过使用映射和集合来快速创建自己的类型。见这里:

    http://paste.lisp.org/display/89840

    编辑(我应该把它粘贴进去,因为它太小了)

    示例代码(由 Stuart Sierra 提供)

    (ns #^{:doc "A multimap is a map that permits multiple values for each
      key.  In Clojure we can represent a multimap as a map with sets as
      values."}
      multimap
      (:use [clojure.set :only (union)]))
    
    (defn add
      "Adds key-value pairs the multimap."
      ([mm k v]
         (assoc mm k (conj (get mm k #{}) v)))
      ([mm k v & kvs]
         (apply add (add mm k v) kvs)))
    
    (defn del
      "Removes key-value pairs from the multimap."
      ([mm k v]
         (let [mmv (disj (get mm k) v)]
           (if (seq mmv)
             (assoc mm k mmv)
             (dissoc mm k))))
      ([mm k v & kvs]
         (apply del (del mm k v) kvs)))
    
    (defn mm-merge
      "Merges the multimaps, taking the union of values."
      [& mms]
      (apply (partial merge-with union) mms))
    
    (comment
      (def mm (add {} :foo 1 :foo 2 :foo 3))
      ;; mm == {:foo #{1 2 3}}
    
      (mm-merge mm (add {} :foo 4 :bar 2))
      ;;=> {:bar #{2}, :foo #{1 2 3 4}}
    
      (del mm :foo 2)
      ;;=> {:foo #{1 3}}
    )
    

    对cmets中指出的情况进行额外测试:

    (comment
      (-> {} (add :a 1) (del :a 1) (contains? :a))
      ;;=> false
    )
    

    【讨论】:

    • 我要补充一点,我不知道与 Google Guava's MultiMap 相比的相对性能,但由于 Clojure 具有非常好的 Java 互操作性,如果你想要的是,它可能很容易包装它.
    • 最好将该代码复制到您的答案中(使用适当的属性等),这样您的答案就可以独立存在,以防链接失效。
    • 请注意(-> {} (add :a 1) (del :a 1) (contains? :a) ;=> true,这会让很多用户感到惊讶。对del 稍作修改即可解决此问题。
    • 确实,paste.lisp.org 已被禁用。
    猜你喜欢
    • 1970-01-01
    • 2015-08-02
    • 1970-01-01
    • 2014-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-14
    • 2011-11-04
    相关资源
    最近更新 更多