在Clojure中映射一个地图值的函数

我想要使​​用相同的键将一个值的地图转换为另一个地图,但是将值应用于一个函数。 我认为在clojure api中有这样做的function,但我一直无法find它。

这是我正在寻找的一个示例实现

(defn map-function-on-map-vals [mf] (reduce (fn [altered-map [kv]] (assoc altered-map k (fv))) {} m)) (println (map-function-on-map-vals {:a "test" :b "testing"} #(.toUpperCase %))) {:b TESTING, :a TEST} 

有没有人知道map-function-on-map-vals已经存在? 我会认为它(也可能有一个更好的名字)。

我喜欢你的reduce版本就好了。 我认为这是惯用的。 这里是一个使用列表理解的版本。

 (defn foo [mf] (into {} (for [[kv] m] [k (fv)]))) 

你可以使用clojure.algo.generic.functor/fmap

 user=> (use '[clojure.algo.generic.functor :only (fmap)]) nil user=> (fmap inc {:a 1 :b 3 :c 5}) {:a 2, :b 4, :c 6} 

这是转换地图的一个相当典型的方法。 zipmap需要一个键和一个值列表的列表,并“做正确的事情”生成一个新的Clojure地图。 你也可以把map放在键上来改变它们,或者两者都有。

 (zipmap (keys data) (map #(do-stuff %) (vals data))) 

或者把它包装在你的函数中:

 (defn map-function-on-map-vals [mf] (zipmap (keys m) (map f (vals m)))) 

采取从Clojure食谱,有reduce-kv:

 (defn map-kv [mf] (reduce-kv #(assoc %1 %2 (f %3)) {} m)) 

这是一个相当习惯的方式来做到这一点:

 (defn map-function-on-map-vals [mf] (apply merge (map (fn [[kv]] {k (fv)}) m))) 

例:

 user> (map-function-on-map-vals {1 1, 2 2, 3 3} inc)) {3 4, 2 3, 1 2} 

我是Clojure n00b,所以可能会有更多优雅的解决scheme。 这是我的:

 (def example {:a 1 :b 2 :c 3 :d 4}) (def func #(* % %)) (prn example) (defn remap [mf] (apply hash-map (mapcat #(list % (f (% m))) (keys m)))) (prn (remap example func)) 

匿名function从每个键和它的f'ed值做一个小的2列表。 Mapcat通过地图按键的顺序运行这个函数,并把整个作品连接成一个大的列表。 “应用哈希映射”从该序列创build一个新的映射。 (%m)可能看起来有点奇怪,这是习惯Clojure应用一个键的映射来查找相关的值。

最强烈推荐阅读: Clojure备忘录 。

map-mapmap-map-keysmap-map-values

我知道在Clojure中没有现有的函数,但是这个函数的实现就像你可以自由拷贝的map-map-values 。 它带有两个紧密相关的函数, map-mapmap-map-keys ,这些函数在标准库中也是缺less的:

 (defn map-map "Returns a new map with each key-value pair in `m` transformed by `f`. `f` takes the arguments `[key value]` and should return a value castable to a map entry, such as `{transformed-key transformed-value}`." [fm] (into (empty m) (map #(apply f %) m)) ) (defn map-map-keys [fm] (map-map (fn [key value] {(f key) value}) m) ) (defn map-map-values [fm] (map-map (fn [key value] {key (f value)}) m) ) 

用法

你可以像这样调用map-map-values

 (map-map-values str {:a 1 :b 2}) ;; => {:a "1", :b "2"} 

另外两个function是这样的:

 (map-map-keys str {:a 1 :b 2}) ;; => {":a" 1, ":b" 2} (map-map (fn [kv] {vk}) {:a 1 :b 2}) ;; => {1 :a, 2 :b} 

替代实现

如果您只想使用map-map-keysmap-map-values ,而不使用更常用的map-map函数,则可以使用这些不依赖map-map

 (defn map-map-keys [fm] (into (empty m) (for [[key value] m] {(f key) value} ))) (defn map-map-values [fm] (into (empty m) (for [[key value] m] {key (f value)} ))) 

另外,下面是一个基于clojure.walk/walk代替map-map的替代实现,如果你喜欢这个措辞:

 (defn map-map [fm] (clojure.walk/walk #(apply f %) identity m) ) 

Parellel版本 – pmap-map

如果你需要的话,也有这些函数的并行版本。 他们只是使用pmap而不是map

 (defn pmap-map [fm] (into (empty m) (pmap #(apply f %) m)) ) (defn pmap-map-keys [fm] (pmap-map (fn [key value] {(f key) value}) m) ) (defn pmap-map-values [fm] (pmap-map (fn [key value] {key (f value)}) m) ) 

我喜欢你的reduce版本。 只有非常微小的变化,它也可以保留logging结构的types:

 (defn map-function-on-map-vals [mf] (reduce (fn [altered-map [kv]] (assoc altered-map k (fv))) mm)) 

{}m代替。 随着这一变化,logging仍然是logging:

 (defrecord Person [firstname lastname]) (def p (map->Person {})) (class p) '=> Person (class (map-function-on-map-vals p (fn [v] (str v)))) '=> Person 

{}开始,如果您希望loggingfunction(例如,紧凑的内存表示forms),则logging失去其logging性 ,可能希望保留该logging。