在 Clojure 中将函数映射到映射的值

发布于 2024-08-10 06:07:25 字数 414 浏览 6 评论 0原文

我想将一个值映射转换为具有相同键但对值应用了函数的另一个映射。我认为 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}

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

I want to transform one map of values to another map with the same keys but with a function applied to the values. I would think there was a function for doing this in the clojure api, but I have been unable to find it.

Here's an example implementation of what I'm looking for

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

Does anybody know if map-function-on-map-vals already exists? I would think it did (probably with a nicer name too).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

梦境 2024-08-17 06:07:25

我很喜欢你的 reduce 版本。我认为这是惯用的。无论如何,这是一个使用列表理解的版本。

(defn foo [m f]
  (into {} (for [[k v] m] [k (f v)])))

I like your reduce version just fine. I think it's idiomatic. Here's a version using list comprehension anyways.

(defn foo [m f]
  (into {} (for [[k v] m] [k (f v)])))
爱冒险 2024-08-17 06:07:25

您可以使用 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}

You can use the 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}
云朵有点甜 2024-08-17 06:07:25

这是一种相当典型的转换地图的方法。
zipmap 接受一个键列表和一个值列表,并“做正确的事情”,生成一个新的 Clojure 映射。您还可以将 map 放在按键周围来更改它们,或两者都更改。

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

或者将其包装在您的函数中:

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

Here is a fairly typical way to transform a map.
zipmap takes a list of keys and a list of values and "does the right thing" producing a new Clojure map. You could also put the map around the keys to change them, or both.

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

or to wrap it up in your function:

(defn map-function-on-map-vals [m f]
    (zipmap (keys m) (map f (vals m))))
冷弦 2024-08-17 06:07:25

摘自《Clojure Cookbook》,有reduce-kv:

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

Taken from the Clojure Cookbook, there is reduce-kv:

(defn map-kv [m f]
  (reduce-kv #(assoc %1 %2 (f %3)) {} m))
放血 2024-08-17 06:07:25

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

update-vals< /a>

(update-vals mf) 将函数应用于映射中的每个值。它返回一个新的映射{k (fv) ...}

用法

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

另请参阅: update-keys

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

Clojure 1.11 中也添加了此功能。

用法

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

Clojure 1.11 added a function for this to clojure.core, the standard library. Clojure 1.11 was released on 2022-03-22.

update-vals

(update-vals m f) applies the function to every value in the map. It returns a new map {k (f v) ...}.

Usage

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

See also: update-keys

(update-keys m f) applies the function to every key in the map. It returns a new map {(f k) v ...}. All keys resulting from (f k) must be unique.

This function, too, was added in Clojure 1.11.

Usage

(update-keys {:a 1 :b 2} str)
;;        => {":a" 1, ":b" 2}
赏烟花じ飞满天 2024-08-17 06:07:25

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

(defn map-function-on-map-vals [m f]
        (apply merge
               (map (fn [[k v]] {k (f v)})
                    m)))

示例:

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

Here's a fairly idiomatic way to do this:

(defn map-function-on-map-vals [m f]
        (apply merge
               (map (fn [[k v]] {k (f v)})
                    m)))

Example:

user> (map-function-on-map-vals {1 1, 2 2, 3 3} inc))
{3 4, 2 3, 1 2}
享受孤独 2024-08-17 06:07:25

map-mapmap-map-keysmap-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) )

用法

您可以调用 map- map-values 像这样:

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

另外两个函数像这样:

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

替代实现

如果您只想要 map-map-keysmap-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)} )))

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

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

并行版本 - pmap-map 等。

如果您需要,这些函数也有并行版本。他们只是使用 pmap 而不是 地图

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

map-map, map-map-keys, and map-map-values

I know of no existing function in Clojure for this, but here’s an implementation of that function as map-map-values that you are free to copy. It comes with two closely related functions, map-map and map-map-keys, which are also missing from the standard library:

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

Usage

You can call map-map-values like this:

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

And the other two functions like this:

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

Alternative implementations

If you only want map-map-keys or map-map-values, without the more general map-map function, you can use these implementations, which don’t rely on 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)} )))

Also, here’s an alternative implementation of map-map that is based on clojure.walk/walk instead of into, if you prefer this phrasing:

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

Parellel versions – pmap-map, etc.

There are also parallel versions of these functions if you need them. They simply use pmap instead of 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) )
薯片软お妹 2024-08-17 06:07:25

我是 Clojure n00b,所以很可能有更优雅的解决方案。这是我的:

(def example {:a 1 :b 2 :c 3 :d 4})
(def func #(* % %))

(prn example)

(defn remap [m f]
  (apply hash-map (mapcat #(list % (f (% m))) (keys m))))

(prn (remap example func))

anon func 根据每个键及其 f'ed 值创建一个小 2-列表。 Mapcat 在地图键的序列上运行此函数,并将整个作品连接成一个大列表。 “apply hash-map”根据该序列创建一个新的映射。 (% m) 可能看起来有点奇怪,它是 Clojure 的惯用用法,用于将键应用于映射以查找关联的值。

最强烈推荐阅读:Clojure Cheat Sheet

I'm a Clojure n00b, so there may well be much more elegant solutions. Here's mine:

(def example {:a 1 :b 2 :c 3 :d 4})
(def func #(* % %))

(prn example)

(defn remap [m f]
  (apply hash-map (mapcat #(list % (f (% m))) (keys m))))

(prn (remap example func))

The anon func makes a little 2-list from each key and its f'ed value. Mapcat runs this function over the sequence of the map's keys and concatenates the whole works into one big list. "apply hash-map" creates a new map from that sequence. The (% m) may look a little weird, it's idiomatic Clojure for applying a key to a map to look up the associated value.

Most highly recommended reading: The Clojure Cheat Sheet .

傲娇萝莉攻 2024-08-17 06:07:25

我喜欢你的 reduce 版本。通过非常微小的变化,它还可以保留记录结构的类型:

(defn map-function-on-map-vals [m f]
  (reduce (fn [altered-map [k v]] (assoc altered-map k (f v))) m m))

{}m 替换。进行此更改后,记录仍然是记录:

(defrecord Person [firstname lastname])

(def p (map->Person {}))
(class p) '=> Person

(class (map-function-on-map-vals p
  (fn [v] (str v)))) '=> Person

通过以 {} 开头,记录将失去其记录性,如果您需要记录功能(紧凑内存),则可能希望保留该记录性例如代表)。

I like your reduce version. With a very slight variation, it can also retain the type of records structures:

(defn map-function-on-map-vals [m f]
  (reduce (fn [altered-map [k v]] (assoc altered-map k (f v))) m m))

The {} was replaced by m. With that change, records remain records:

(defrecord Person [firstname lastname])

(def p (map->Person {}))
(class p) '=> Person

(class (map-function-on-map-vals p
  (fn [v] (str v)))) '=> Person

By starting with {}, the record loses its recordiness, which one might want to retain, if you desire the record capabilities (compact memory representation for instance).

罗罗贝儿 2024-08-17 06:07:25
(defn map-vals
  "Map f over every value of m.
   Returns a map with the same keys as m, where each of its values is now the result of applying f to them one by one.
   f is a function of one arg, which will be called which each value of m, and should return the new value.
   Faster then map-vals-transient on small maps (8 elements and under)"
  [f m]
  (reduce-kv (fn [m k v]
               (assoc m k (f v)))
             {} m))

(defn map-vals-transient
  "Map f over every value of m.
   Returns a map with the same keys as m, where each of its values is now the result of applying f to them one by one.
   f is a function of one arg, which will be called which each value of m, and should return the new value.
   Faster then map-vals on big maps (9 elements or more)"
  [f m]
  (persistent! (reduce-kv (fn [m k v]
                            (assoc! m k (f v)))
                          (transient {}) m)))
(defn map-vals
  "Map f over every value of m.
   Returns a map with the same keys as m, where each of its values is now the result of applying f to them one by one.
   f is a function of one arg, which will be called which each value of m, and should return the new value.
   Faster then map-vals-transient on small maps (8 elements and under)"
  [f m]
  (reduce-kv (fn [m k v]
               (assoc m k (f v)))
             {} m))

(defn map-vals-transient
  "Map f over every value of m.
   Returns a map with the same keys as m, where each of its values is now the result of applying f to them one by one.
   f is a function of one arg, which will be called which each value of m, and should return the new value.
   Faster then map-vals on big maps (9 elements or more)"
  [f m]
  (persistent! (reduce-kv (fn [m k v]
                            (assoc! m k (f v)))
                          (transient {}) m)))
你在我安 2024-08-17 06:07:25

我想知道为什么还没有人提到 specter 库。它的编写是为了使这种转换易于编码(更重要的是,编写的代码易于理解),同时仍然非常高效:

(require '[com.rpl.specter :as specter])

(defn map-vals [m f]
  (specter/transform
   [specter/ALL specter/LAST]
   f m))

(map-vals {:a "test" :b "testing"}
          #(.toUpperCase %))

用纯 Clojure 编写这样的函数很简单,但代码变得更加棘手一旦您转向由不同数据结构组成的高度嵌套的代码。这就是幽灵的用武之地。

我建议观看这一集 解释了 spectre 背后的动机和细节。

I'm wondering why nobody has mentioned the specter library yet. It has been written to make this kind of transform easy to code (and, even more important, the written code easy to understand), while still being very performant:

(require '[com.rpl.specter :as specter])

(defn map-vals [m f]
  (specter/transform
   [specter/ALL specter/LAST]
   f m))

(map-vals {:a "test" :b "testing"}
          #(.toUpperCase %))

Writing such a function in pure Clojure is simple, but the code gets much trickier once you move on to highly nested code composed of different data structures. And this is where specter comes in.

I recommend watching this episode on Clojure TV which explains the motivation behind and details of specter.

晨与橙与城 2024-08-17 06:07:25

Clojure 1.7(发布 2015 年 6 月 30 日)提供了一个优雅的解决方案与 update 一起使用:

(defn map-function-on-map-vals [m f]
    (->> (map #(update % 1 f) m)
         (into {})))

(map-function-on-map-vals {:a "test" :b "testing"} #(.toUpperCase %))
;; => {:a "TEST", :b "TESTING"}

Clojure 1.7 (released June 30, 2015) provides an elegant solution for this with update:

(defn map-function-on-map-vals [m f]
    (->> (map #(update % 1 f) m)
         (into {})))

(map-function-on-map-vals {:a "test" :b "testing"} #(.toUpperCase %))
;; => {:a "TEST", :b "TESTING"}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文