Pregunta

Quiero transformar un mapa de valores a otro mapa con las mismas claves, pero con una función aplicada a los valores. Yo creo que había una función para hacer esto en el API clojure, pero no he sido capaz de encontrarlo.

El siguiente es un ejemplo de implementación 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? Me gustaría pensar que lo hizo (probablemente con un nombre más bonito también).

¿Fue útil?

Solución

Me gusta su versión reduce bien. Creo que es idiomática. Aquí está utilizando una versión lista por comprensión de todos modos.

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

Otros consejos

Puede utilizar el 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}

Aquí está una manera bastante típico para transformar un mapa. zipmap toma una lista de claves y una lista de valores y "hace lo correcto" producir un nuevo mapa Clojure. También puede poner el map alrededor de las teclas de cambiarlos, o ambos.

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

o para envolverlo en su función:

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

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

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

Esto es una forma bastante idiomática para hacer esto:

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

Ejemplo:

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

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

No conozco ninguna función existente en Clojure para esto, pero aquí es una implementación de esta función como map-map-values que son libres de copiar. Viene con dos funciones estrechamente relacionadas, y map-map map-map-keys, que también están ausentes de 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 map-map-values como esto:

(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 sólo desea map-map-keys o map-map-values, sin la función map-map más general, puede utilizar 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í es una implementación alternativa de map-map que se basa en clojure.walk/walk en lugar de < a href = "http://clojuredocs.org/clojure_core/clojure.core/into" rel = "nofollow"> into , si se prefiere esta frase:

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

versiones Parellel -. pmap-map, etc.

También hay versiones paralelas de estas funciones, si los necesita. Simplemente utilizan pmap en 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) )

Soy un n00b Clojure, por lo que es muy posible que las soluciones más elegantes. Esta es la mía:

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

La func anon hace un poco más de 2 Lista de vehículos de cada tecla y su valor f'ed. Mapcat se ejecuta esta función durante la secuencia de teclas del mapa y concatena el conjunto de obras en una lista grande. "Hash aplica un mapa" crea un nuevo mapa de esa secuencia. El (% m) puede parecer un poco raro, es idiomática Clojure para aplicar una llave de un mapa para buscar el valor asociado.

La mayoría de lectura muy recomendable:. El Clojure Hoja de trucos

Me gusta su versión reduce. Con una muy ligera variación, también puede retener el tipo de estructuras de entradas:

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

El {} fue reemplazado por m. Con este cambio, los registros se mantienen 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 recordiness , que uno podría desear conservar, si lo desea las capacidades de registro (representación compacta de memoria, por ejemplo).

(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)))
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top