5

こんにちはhuys:マップ内のすべての値の「平均」をマップしたいと思います。マップのリストがあるとします:

[{"age" 2 "height" 1 "weight" 10},
{"age" 4 "height" 4 "weight" 20},
{"age" 7 "height" 11 "weight" 40}]

そして、私の望ましい出力は

{"age 5 "height" 5 ....}

///以下は私の頭の中のとりとめのないものです。つまり、Clojure でこれが機能することを想像する方法です...あまり真剣に受け止めないでください

リストを転置します:

  {"age" [2 4 7] "height" [1 4 11] } 

次に、次のようなことを簡単に行うことができます (ここでも、freduce という関数を作成します)。

  (freduce average (vals (map key-join list)))

取得するため

{"age" 5 "weight" 10 "height" 7}

4

6 に答える 6

6

ベクトルのマップを作成します。

((fn [m [kv]] を減らす)
          (assoc mk (conj (get mk []) v)))
        {}
        (concat list-of-maps を適用))

平均のマップを作成します。

((fn [m [kv]] を減らす)
          (assoc mk (/ (reduce + v) (count v))))
        {}
        ベクトルのマップ)
于 2011-10-23T08:58:12.210 に答える
5

merge-with を見てみましょう

これが私の実際のコードです:

(let [maps [{"age" 2 "height" 1 "weight" 10},
            {"age" 4 "height" 4 "weight" 20},
            {"age" 7 "height" 11 "weight" 40}]]
  (->> (apply merge-with #(conj %1 %2)
             (zipmap (apply clojure.set/union (map keys maps))
                     (repeat [])) ; set the accumulator
             maps)
       (map (fn [[k v]] [k (/ (reduce + v) (count v))]))
       (into {})))
于 2011-10-23T05:34:55.947 に答える
4

これはかなり冗長な解決策です。うまくいけば、誰かがより良いものを思いつくことができます:

(let [maps [{"age" 2 "height" 1 "weight" 10},
            {"age" 4 "height" 4 "weight" 20},
            {"age" 7 "height" 11 "weight" 40}]
      ks (keys (first maps))
      series-size (count maps)
      avgs (for [k ks]
             (/ (reduce +
                        (for [m maps]
                          (get m k)))
                series-size))]
  (zipmap ks avgs))
于 2011-10-23T06:07:24.597 に答える
2
(defn key-join [map-list]
  (let [keys (keys (first map-list))]
       (into {} (for [k keys] [k (map #(% k) map-list)]))))
(defn mapf [f map]
  (into {} (for [[k v] map ] [k (f v)])))
(defn average [col]
  (let [n (count col)
        sum (apply + col)]
       (/ sum n)))

デモ

user=> (def data-list [{"age" 2 "height" 1 "weight" 10},
{"age" 4 "height" 4 "weight" 20},
{"age" 7 "height" 11 "weight" 40}])
#'user/data-list
user=> (key-join data-list)
{"age" (2 4 7), "height" (1 4 11), "weight" (10 20 40)}
user=> (mapf average (key-join data-list))
{"age" 13/3, "height" 16/3, "weight" 70/3}
于 2011-10-23T11:11:21.127 に答える
1

これは、zipmapなしでmerge-withを使用する別のバージョンです。

(let [data [{:a 1 :b 2} {:a 2 :b 4} {:a 4 :b 8}]
           num-vals (count data)]
     (->> data (apply merge-with +) 
          (reduce (fn [m [k v]] (assoc m k (/ v num-vals))) {})))
于 2011-10-23T10:40:36.880 に答える
1

これが私のワンライナーソリューションです:

(def d [{"age" 2 "height" 1 "weight" 10},
   {"age" 4 "height" 4 "weight" 20},
   {"age" 7 "height" 11 "weight" 40}])

(into {} (map (fn [[k v] [k (/ v (count d))]]) (apply merge-with + d)))

=> {"height" 16/3, "weight" 70/3, "age" 13/3}

ロジックは次のとおりです。

  • マップで + とのマージを使用して、各キー値の合計を計算します
  • 結果のすべての値をマップの総数で割り、平均を求めます。
  • ({} ...) を使用して、結果をハッシュマップに戻します。
于 2011-11-24T16:28:06.677 に答える