List 我可以吗;转置;在Clojure中将地图列表转换为列表地图?

List 我可以吗;转置;在Clojure中将地图列表转换为列表地图?,list,map,clojure,transpose,List,Map,Clojure,Transpose,嗨,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] "

嗨,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的函数)

得到

{“年龄”5“体重”10“身高”7}

看看

下面是我的一些实际代码:

(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 {})))

这里有一个相当详细的解决方案。希望有人能想出更好的办法:

(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))

创建矢量图:

(reduce (fn [m [k v]] (assoc m k (conj (get m k []) v))) {} (apply concat list-of-maps)) (减少(fn[m[k v]] (assocmk(conj(get mk[])v))) {} (应用concat地图列表) 创建平均值地图:

(reduce (fn [m [k v]] (assoc m k (/ (reduce + v) (count v)))) {} map-of-vectors) (减少(fn[m[k v]] (关联m k(/(减少+v)(计数v))) {} 矢量图)
下面是另一个版本,它使用merge with with with without zipmap

(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))) {})))
演示

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}

以下是我的一行解决方案:

(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}
逻辑如下:

  • 在地图上使用“与+合并”来计算每个键值的总和
  • 将所有结果值除以贴图总数以获得平均值
  • 将结果放回具有(到{}…)的hashmap中

您需要减少,这样就不必遍历序列两次。您将以一个空映射作为累加器开始,当reduce到达每个映射时,将所有值与累加器中的相应值相加。在列表的最后一个元素上,将每个值除以列表的长度。实际上,我想对数据进行更复杂的数学处理(标准差,…),因此我想我想将数据合并的方式与转置的方式分离。这假设所有的键都存在于所有的映射中,这可能是一个毫无根据的假设(至少不明确)。您的关键点假设是正确的,如果某些贴图缺少关键点,则需要将
+
合并为
#(+(或%1 0)(或%2 0))
我认为,你的解决方案是正确的,因为它可读性很强。这很优雅,但在这一点上对我来说可能有点太高级了。感谢你指点我合并,我会学到它…似乎有道理。不确定平均值应用在哪里…我想是mapf>?如果你说如果函数名。>不确定平均值应用于何处。平均值应用于地图数据值(集合)。“平均值”不会应用于地图键。更不用说,减少(!)平均地图数据。感谢您的解释…有意义。
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}
(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}