[Dictionary] Mapeo de una función en los valores de un mapa en Clojure



Answers

Puede usar 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}
Question

Quiero transformar un mapa de valores en otro mapa con las mismas teclas pero con una función aplicada a los valores. Pensaría que había una función para hacer esto en la API de Clojure, pero no he podido encontrarla.

Aquí hay una implementación de ejemplo de lo que estoy buscando

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

¿Alguien sabe si map-function-on-map-vals ya existe? Creo que sí (probablemente con un nombre más agradable también).




Me gusta tu versión reducida. Con una ligera variación, también puede conservar el tipo de estructuras de registros:

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

{} Fue reemplazado por m . Con ese cambio, los registros siguen siendo registros:

(defrecord Person [firstname lastname])

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

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

Al comenzar con {} , el registro pierde su capacidad de grabar , que es posible que desee retener, si desea las capacidades de grabación (por ejemplo, representación de memoria compacta).




map-map , map-map-keys , y map-map-values

No conozco ninguna función existente en Clojure para esto, pero aquí hay una implementación de esa función como map-map-values que puede copiar. Viene con dos funciones estrechamente relacionadas, map-map y map-map-keys , que también faltan en la biblioteca estándar:

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

Uso

Puede llamar a map-map-values esta manera:

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

Y las otras dos funciones como esta:

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

Implementaciones alternativas

Si solo quiere map-map-keys o map-map-values , sin la función más general de map-map , puede usar estas implementaciones, que no se basan en 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)} )))

Además, aquí hay una implementación alternativa de map-map que se basa en clojure.walk/walk lugar de into , si prefieres este fraseo:

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

Versiones de Parellel - pmap-map , etc.

También hay versiones paralelas de estas funciones si las necesita. Simplemente usan pmap lugar de 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) )



Tomado del libro de cocina Clojure, hay reduce-kv:

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



Links