在Clojure中映射关于地图值的函数

Tho*_*mas 129 dictionary clojure map-function

我想将一个值映射转换为另一个具有相同键但具有应用于值的函数的映射.我认为在clojure api中有这样做的功能,但我一直无法找到它.

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

(defn map-function-on-map-vals [m f]
  (reduce (fn [altered-map [k v]] (assoc altered-map k (f v))) {} m))
(println (map-function-on-map-vals {:a "test" :b "testing"} #(.toUpperCase %)))
{:b TESTING, :a TEST}
Run Code Online (Sandbox Code Playgroud)

有人知道是否map-function-on-map-vals已经存在?我认为它确实(可能还有一个更好的名字).

Bri*_*per 143

我很喜欢你的reduce版本.我认为这是惯用的.这是一个使用列表理解的版本.

(defn foo [m f]
  (into {} (for [[k v] m] [k (f v)])))
Run Code Online (Sandbox Code Playgroud)

  • 我强烈建议使用 (empty m) 而不是 {}。所以它仍然是一种特定类型的地图。 (4认同)
  • 我喜欢它,但是参数顺序有什么理由吗(除了问题)?出于某种原因,我期待 [fm] 就像在 `map` 中一样。 (3认同)
  • 我喜欢这个版本,因为如果您了解它使用的所有功能等,它就会非常简短且显而易见。如果你不这样做,这就是学习它们的借口! (2认同)

Art*_*ein 93

你可以使用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}
Run Code Online (Sandbox Code Playgroud)

  • generic.function lib已经移动到一个单独的库:`org.clojure/algo.generic"0.1.0"`这个例子现在应该是:`(使用'[clojure.algo.generic.functor:only(fmap)] )(fmap inc {:a 1:b 3:c 5})` (13认同)
  • 知道如何在ClojureScript中找到`fmap`吗? (2认同)

Art*_*ldt 33

这是一种转换地图的典型方法. zipmap 获取一个键列表和一个值列表,并"做正确的事"产生一个新的Clojure映射.您也可以放置map密钥来更改它们,或两者兼而有之.

(zipmap (keys data) (map #(do-stuff %) (vals data)))
Run Code Online (Sandbox Code Playgroud)

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

(defn map-function-on-map-vals [m f]
    (zipmap (keys m) (map f (vals m))))
Run Code Online (Sandbox Code Playgroud)

  • Rob:是的,键和val将对所有地图使用相同的顺序 - 与地图上的seq使用的顺序相同.由于散列,排序和数组映射都是不可变的,因此订单不可能在平均时间内发生变化. (4认同)
  • 我们是否保证键和值以相同的顺序返回相应的值?对于排序映射和哈希映射? (2认同)
  • 情况确实如此,但它是否记录在任何地方?至少key和vals的docstrings没有提到这一点.如果我可以指出一些承诺它会起作用的官方文档,我会更习惯使用它. (2认同)
  • @Jason 是的,我认为他们将其添加到 1.6 版的文档中。http://dev.clojure.org/jira/browse/CLJ-1302 (2认同)

Ror*_*ane 23

Clojure 1.11clojure.core在标准库中添加了一个函数。Clojure 1.11于 2022 年 3 月 22 日发布。

update-vals

(update-vals m f)将函数应用于映射中的每个值。它返回一张新地图{k (f v) ...}

用法

(update-vals {:a 1 :b 2} str)
;;        => {:a "1", :b "2"}
Run Code Online (Sandbox Code Playgroud)

也可以看看: update-keys

(update-keys m f)将函数应用于映射中的每个键。它返回一张新地图{(f k) v ...}。产生的所有键(f k)必须是唯一的。

Clojure 1.11 中也添加了此功能。

用法

(update-keys {:a 1 :b 2} str)
;;        => {":a" 1, ":b" 2}
Run Code Online (Sandbox Code Playgroud)


rob*_*oli 19

从Clojure Cookbook中获取,有reduce-kv:

(defn map-kv [m f]
  (reduce-kv #(assoc %1 %2 (f %3)) {} m))
Run Code Online (Sandbox Code Playgroud)


Sid*_*ddy 8

这是一个相当惯用的方法:

(defn map-function-on-map-vals [m f]
        (apply merge
               (map (fn [[k v]] {k (f v)})
                    m)))
Run Code Online (Sandbox Code Playgroud)

例:

user> (map-function-on-map-vals {1 1, 2 2, 3 3} inc))
{3 4, 2 3, 1 2}
Run Code Online (Sandbox Code Playgroud)

  • 如果不清楚:anon函数*将*k*和*v*的键和值解构,然后返回哈希映射映射*k*到*(fv)*. (2认同)

Ror*_*ane 6

map-map, map-map-keys, 和map-map-values

我知道 Clojure 中没有现有的函数用于此,但这里是该函数的实现,因为map-map-values您可以自由复制。它带有两个密切相关的函数map-mapmap-map-keys,标准库中也没有:

(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}`."
    [f m]
    (into (empty m) (map #(apply f %) m)) )

(defn map-map-keys [f m]
    (map-map (fn [key value] {(f key) value}) m) )

(defn map-map-values [f m]
    (map-map (fn [key value] {key (f value)}) m) )
Run Code Online (Sandbox Code Playgroud)

用法

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

(map-map-values str {:a 1 :b 2})
;;           => {:a "1", :b "2"}
Run Code Online (Sandbox Code Playgroud)

其他两个函数是这样的:

(map-map-keys str {:a 1 :b 2})
;;         => {":a" 1, ":b" 2}
(map-map (fn [k v] {v k}) {:a 1 :b 2})
;;    => {1 :a, 2 :b}
Run Code Online (Sandbox Code Playgroud)

替代实现

如果你只想要map-map-keysor map-map-values,没有更通用的map-map功能,你可以使用这些不依赖于的实现map-map

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

(defn map-map-values [f m]
    (into (empty m)
        (for [[key value] m]
            {key (f value)} )))
Run Code Online (Sandbox Code Playgroud)

此外,如果您更喜欢这种措辞,这里有一个map-map基于clojure.walk/walk而不是的替代实现into

(defn map-map [f m]
    (clojure.walk/walk #(apply f %) identity m) )
Run Code Online (Sandbox Code Playgroud)

并行版本 –pmap-map等。

如果您需要,还有这些功能的并行版本。他们只是使用pmap而不是map.

(defn pmap-map [f m]
    (into (empty m) (pmap #(apply f %) m)) )
(defn pmap-map-keys [f m]
    (pmap-map (fn [key value] {(f key) value}) m) )
(defn pmap-map-values [f m]
    (pmap-map (fn [key value] {key (f value)}) m) )
Run Code Online (Sandbox Code Playgroud)