5

Clojureを使用して、慣用的に複数のマップを単一のマップにマージしようとしています。

入力

{:a 1 :b "a"}
{:a 2 :b "b"}
{:a 3 :b "c"}
{:a 4 :b "a"}

期待される

{:a #{1,2,3,4}, :b #{"a" "b" "c"}} 

各キーの値は、元のマップの一連の値に変換されます。

4

7 に答える 7

5

merge-with空のセットを含む事前構築済みの構造を使用して、 を使用します。

(def data [{:a 1 :b "a"}
           {:a 2 :b "b"}
           {:a 3 :b "c"}
           {:a 4 :b "a"}])

(let [base {:a #{} :b #{}}]
  (apply merge-with conj base data))

=> {:a #{1 2 3 4}, :b #{"a" "b" "c"}}

ベース マップで空のセットを使用する秘訣は、conj動作する具体的なオブジェクトがあるため、正しく動作することです。

于 2012-06-27T14:48:52.203 に答える
4

merge-with次のように使用できます。

(def d [{:a 1 :b "a"}
        {:a 2 :b "b"}
        {:a 3 :b "c"}
        {:a 4 :b "a"}])

(def initial (into {} (map #(vector  %1 [])  (keys (apply merge d)))))

(into {} (map (fn [[a b]] [a (set b)]) 
           (apply merge-with (fn [a b] (conj a b)) initial  d)))
于 2012-06-27T12:18:24.640 に答える
2
(defn value-sets [& maps]
  (reduce (fn [acc map]
            (reduce (fn [m [k v]]
                      (update-in m [k] (fnil conj #{}) v))
                    acc
                    map))
          {} maps))

編集するか多分

(defn value-sets [& maps]
  (reduce (fn [acc [k v]]
            (update-in acc [k] (fnil conj #{}) v))
          {}
          (apply concat maps)))

さらに編集して、何年も後に:私はこれを別の方法で書きます:

(defn value-sets [maps]
  (apply merge-with into (for [m maps, [k v] m] 
                           {k #{v}})))
于 2012-06-27T18:44:00.353 に答える
1

アマロイの解決策を見てreduce、これが私に示唆されました:

(def maps [{:a 1 :b 2}
           {:a 11 :b 22 :c 5}
           {:c 6 :a 7}])

(defn my-merge-maps
  [maps]
  (reduce (fn [accum [k v]]
            (if (accum k)
              (assoc accum k (conj (accum k) v))
              (assoc accum k #{v})))
          {}
          (apply concat maps)))

(defn -main
  []
  (println (my-merge-maps maps)))

結果は次のとおりです。{:c #{5 6}, :b #{2 22}, :a #{1 7 11}}

(誤って可変引数を使用していたことを指摘してくれた gfredericks に感謝します。:))

編集:そして、次を使用した別の方法がありmerge-withます:

(def maps [{:a 1 :b 2}
           {:a 11 :b 22 :c 5}
           {:c 6 :a 7}])

(defn build-up-set
  [curr-val new-val]
  (if (set? curr-val)
    (conj curr-val new-val)
    #{curr-val new-val}))

(defn my-merge-maps
  [maps]
  (apply merge-with build-up-set maps))

(defn -main
  []
  (println (my-merge-maps maps)))
于 2012-06-28T19:24:58.633 に答える
0
(def data [{:a 1 :b "a"}
           {:a 2 :b "b"}
           {:a 3 :b "c"}
           {:a 4 :b "a"}])

(apply
  merge-with
  clojure.set/union
  (map #(zipmap (keys %) (map hash-set (vals %))) data))
;{:b #{"a" "b" "c"}, :a #{1 2 3 4}}
于 2014-07-19T08:47:33.570 に答える
0

Amalloy は、昨日 IRC で同じ問題について次のソリューションをドロップしました。

(defn value-sets [& maps]                                                      
  (apply merge-with into (for [m maps, [k v] m] {k #{v}})))
于 2017-05-30T08:37:55.857 に答える