代码之家  ›  专栏  ›  技术社区  ›  Alex Miller

合并地图列表并将值合并到Clojure中的集合

  •  12
  • Alex Miller  · 技术社区  · 16 年前

    我能放什么功能 到最后还是要屈服?我使用了散列集(只对前2个值正确)、conj和concat,但我知道我没有正确地使用其中的任何一个来处理单元素与集条件。

    (defn mergeMatches [propertyMapList]
        "Take a list of maps and merges them combining values into a set"
        (reduce #(merge-with FOO %1 %2) {} propertyMapList))
    
    (def in 
        (list
            {:a 1}
            {:a 2}
            {:a 3}
            {:b 4}
            {:b 5}
            {:b 6} ))
    
    (def out
        { :a #{ 1 2 3}
          :b #{ 4 5 6} })
    
    ; this should return true
    (= (mergeMatches in) out)
    

    处理这个问题最惯用的方法是什么?

    6 回复  |  直到 16 年前
        1
  •  12
  •   Alex Miller    16 年前

    这样做:

    (let [set #(if (set? %) % #{%})]
      #(clojure.set/union (set %) (set %2)))
    

    直接重写示例(alex):

    (defn to-set [s]
        (if (set? s) s #{s}))
    (defn set-union [s1 s2] 
        (clojure.set/union (to-set s1) (to-set s2)))
    (defn mergeMatches [propertyMapList]
        (reduce #(merge-with set-union %1 %2) {} propertyMapList))
    
        2
  •  5
  •   Alex Miller    16 年前

    我没有写这个,但它是 contributed 通过 @amitrathore Twitter :

    (defn kv [bag [k v]] 
      (update-in bag [k] conj v))
    (defn mergeMatches [propertyMapList]
      (reduce #(reduce kv %1 %2) {} propertyMapList))
    
        3
  •  4
  •   Timothy Pratley    16 年前

    我不会用merge with来做这个,

    (defn fnil [f not-found]
      (fn [x y] (f (if (nil? x) not-found x) y)))
    (defn conj-in [m map-entry]
      (update-in m [(key map-entry)] (fnil conj #{}) (val map-entry)))
    (defn merge-matches [property-map-list]
      (reduce conj-in {} (apply concat property-map-list)))
    
    user=> (merge-matches in)
    {:b #{4 5 6}, :a #{1 2 3}}
    

    FNIL将很快成为核心的一部分,因此您可以忽略实现…但它只是创建了另一个可以处理nil参数的函数版本。在这种情况下,conj将用nil替换。

    因此,对于所提供的映射列表中的每一个键/值,这个约简连接到一个集合。

        4
  •  3
  •   Alex Miller    16 年前

    另一个解决方案是 @wmacgyver Twitter 基于 multimaps :

    (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 mm-merge
      "Merges the multimaps, taking the union of values."
      [& mms]
      (apply (partial merge-with union) mms))   
    
    (defn mergeMatches [property-map-list]
      (reduce mm-merge (map #(add {} (key (first %)) (val (first %))) property-map-list)))      
    
        5
  •  2
  •   Siddhartha Reddy    16 年前

    这似乎有效:

    (defn FOO [v1 v2]
          (if (set? v1)
              (apply hash-set v2 v1)
              (hash-set v1 v2)))
    
        6
  •  2
  •   mac    16 年前

    不是很漂亮,但很管用。

    (defn mergeMatches [propertyMapList]
        (for [k (set (for [pp propertyMapList] (key (first pp))))]
             {k (set (remove nil? (for [pp propertyMapList] (k pp))))}))
    
    推荐文章