在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-map
, map-map-keys
和map-map-values
我知道在Clojure中没有现有的函数,但是这个函数的实现就像你可以自由拷贝的map-map-values
。 它带有两个紧密相关的函数, map-map
和map-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-keys
或map-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。