2

次の問題で悩んでいます...

与えられたマップのコレクション

[
 {:a 1 :b 1 :c 1 :d 1}
 {:a 1 :b 2 :c 1 :d 2}
 {:a 1 :b 2 :c 2 :d 3}
 {:a 2 :b 1 :c 1 :d 5}
 {:a 2 :b 1 :c 1 :d 6}
 {:a 2 :b 1 :c 1 :d 7}
 {:a 2 :b 2 :c 1 :d 7}
 {:a 2 :b 3 :c 1 :d 7}
]

縮小/変換したい...

{
 1 {:b [1 2] :c [1 2] :d [1 2 3]}
 2 {:b [1 2 3] :c 1 :d [5 6 7]}
}

group-by :a (主キー) を使用して、他のキーの個別の値を蓄積します。私はこれをブルートフォース/命令的な方法で行うことができますが、クロージュアの方法でこれを解決する方法を理解するのに苦労しています.

ありがとう

4

4 に答える 4

3

以下は、確かに洗練されていない、最初のドラフトのソリューションです。

(defn reducing-fn [list-of-maps grouping-key]
    (reduce (fn [m [k lst]]
              (assoc m k (dissoc (reduce (fn [m1 m2]
                                           (apply hash-map
                                                  (apply concat
                                                         (for [[k v] m2]
                                                           [k (conj (get m1 k #{}) v)]))))
                                         {}
                                         lst)
                                 grouping-key)))
            {}
            (group-by #(grouping-key %) list-of-maps)))

user> (reducing-fn [{:a 1 :b 1 :c 1 :d 1}
                    {:a 1 :b 2 :c 1 :d 2}
                    {:a 1 :b 2 :c 2 :d 3}
                    {:a 2 :b 1 :c 1 :d 5}
                    {:a 2 :b 1 :c 1 :d 6}
                    {:a 2 :b 1 :c 1 :d 7}
                    {:a 2 :b 2 :c 1 :d 7}
                    {:a 2 :b 3 :c 1 :d 7}] 
                   :a)
=> {2 {:c #{1}, :b #{1 2 3}, :d #{5 6 7}}, 1 {:c #{1 2}, :b #{1 2}, :d #{1 2 3}}}

明日はもっと洗練されたアプローチを見つけようとします。今すぐベッドに向かいます:)

于 2012-05-29T22:43:14.017 に答える
2
(use 'clojure.set)
(def data
  [
   {:a 1 :b 1 :c 1 :d 1}
   {:a 1 :b 2 :c 1 :d 2}
   {:a 1 :b 2 :c 2 :d 3}
   {:a 2 :b 1 :c 1 :d 5}
   {:a 2 :b 1 :c 1 :d 6}
   {:a 2 :b 1 :c 1 :d 7}
   {:a 2 :b 2 :c 1 :d 7}
   {:a 2 :b 3 :c 1 :d 7}
  ]
)

(defn key-join
  "join of map by key , value is distinct."
  [map-list]
  (let [keys (keys (first map-list))]
       (into {} (for [k keys] [k (vec (set (map #(% k) map-list)))]))))

(defn group-reduce [key map-list]
  (let [sdata (set map-list)
        group-value (project sdata [key])]
       (into {}
         (for [m group-value] [(key m) (key-join (map #(dissoc % key) (select #(= (key %) (key m)) sdata)))]))))
;;other version fast than group-reduce 
(defn gr [key map-list]
  (let [gdata (group-by key map-list)]
    (into {} (for [[k m] gdata][k (dissoc (key-join m) key)]))))
user=> (group-reduce :a data)
{1 {:c [1 2], :b [1 2], :d [1 2 3]}, 2 {:c [1], :b [1 2 3], :d [5 6 7]}}
user=> (gr :a data)
{1 {:c [1 2], :b [1 2], :d [1 2 3]}, 2 {:c [1], :b [1 2 3], :d [5 6 7]}}
于 2012-05-30T01:22:44.490 に答える
2

別の解決策:

(defn pivot [new-key m]
  (apply merge 
    (for [[a v] (group-by new-key m)]
      {a (let [ks (set (flatten (map keys (map #(dissoc % new-key) v))))]
            (zipmap ks (for [k ks] (set (map k v)))))})))

ETA: new-key は :a キーで、m は入力マップです。

最初の "for" は group-by を分解します。ここで、入力「新しいキー」によってデータを分割しています。「for」はリストを生成します - これは Python のリスト内包表記のようなものです。ここでは、それぞれが 1 つのキーを持ち、その値がマップであるマップのリストを生成しています。まず、関連するキーを抽出する必要があります。これらのキーは「ks」バインディングに保持されます。個別の値を蓄積したいと考えています。reduce を使用してこれを行うこともできますが、キーワードも関数であるため、それらを使用してコレクション全体を抽出し、「set」を使用して個別の値に減らすことができます。「zipmap」は、キーとそれに関連付けられた値を結び付けます。次に、メインの「for」の外で、このマップのリストを、キーが「a」の個別の値である単一のマップに変換する必要があります。

于 2012-05-30T14:25:17.860 に答える
1

別の解決策:

(defn transform
  [key coll]
  (letfn [(merge-maps
            [coll]
            (apply merge-with (fnil conj #{}) {} coll))
          (process-key
            [[k v]]
            [k (dissoc (merge-maps v) key)])]
    (->> coll
      (group-by #(get % key))
      (map process-key)
      (into (empty coll)))))

ただし、コードはテストされていません。

編集:もちろん、merge-with賢くなりすぎたため、機能しません。

(defn transform
  [key coll]
  (letfn [(local-merge-with
            [f m & ms]
            (reduce (fn [m [k v]] (update-in m [k] f v))
                    m
                    (for [m ms e m] e)))
          (merge-maps
            [coll]
            (apply local-merge-with (fnil conj #{}) {} coll))
          (process-key
            [[k v]]
            [k (dissoc (merge-maps v) key)])]
    (->> coll
      (group-by #(get % key))
      (map process-key)
      (into (empty coll)))))
于 2012-05-30T06:02:34.793 に答える