Question

Je veux transformer une carte de valeurs à une autre carte avec les mêmes touches mais avec une fonction appliquée aux valeurs. Je pense qu'il y avait une fonction pour ce faire dans le api Clojure, mais je suis incapable de le trouver.

Voici un exemple d'implémentation de ce que je suis à la recherche

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

Quelqu'un sait-il si map-function-on-map-vals existe déjà? Je pense qu'il a fait (probablement avec un nom plus agréable aussi).

Était-ce utile?

La solution

J'aime votre version reduce très bien. Je pense qu'il est idiomatiques. Voici une version en utilisant la compréhension de la liste de toute façon.

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

Autres conseils

Vous pouvez utiliser le 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}

Voici une façon assez typique de transformer une carte. zipmap prend une liste de clés et une liste de valeurs et « fait la bonne chose » la production d'une nouvelle carte Clojure. Vous pouvez également mettre le map autour des clés pour les changer, ou les deux.

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

ou de l'envelopper dans votre fonction:

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

Tiré du livre de recettes Clojure, il est de réduire kv:

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

Voici une façon assez idiomatiques faire ceci:

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

Exemple:

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

map-map, map-map-keys et map-map-values

Je ne connais aucune fonction existante dans Clojure pour cela, mais voici une implémentation de cette fonction map-map-values que vous êtes libre de copier. Il est livré avec deux fonctions étroitement liées, et map-map map-map-keys, qui manquent également de la bibliothèque standard:

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

Utilisation

Vous pouvez appeler map-map-values comme ceci:

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

Et les deux autres fonctions comme celle-ci:

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

implémentations alternatives

Si vous ne souhaitez que map-map-keys ou map-map-values, sans la fonction map-map plus générale, vous pouvez utiliser ces mises en œuvre, qui ne reposent pas sur 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)} )))

En outre, voici une implémentation alternative de map-map qui est basé sur clojure.walk/walk au lieu de < a href = "http://clojuredocs.org/clojure_core/clojure.core/into" rel = "nofollow"> into , si vous préférez ce phrasé:

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

versions Parellel -. pmap-map, etc

Il existe aussi des versions parallèles de ces fonctions si vous en avez besoin. Ils utilisent simplement pmap au lieu 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) )

Je suis un n00b Clojure, donc il peut y avoir des solutions beaucoup plus élégantes. Voici le mien:

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

Le func anon fait un petit 2-list de chaque clé et sa valeur f'ed. Mapcat exécute cette fonction sur la séquence des clés de la carte et concaténer l'ensemble des travaux dans une grande liste. « Appliquer le hachage carte » crée une nouvelle carte de cette séquence. Le (% m) peut sembler un peu bizarre, il est Clojure idiomatiques pour appliquer une clé d'une carte pour rechercher la valeur associée.

lecture plus fortement recommandé. Le Clojure Cheat Sheet

J'aime votre version reduce. Avec une très légère variation, il peut aussi conserver le type de structures de dossiers:

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

Le {} a été remplacé par m. Avec ce changement, les dossiers restent les enregistrements:

(defrecord Person [firstname lastname])

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

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

En commençant par {}, le disque perd son recordiness , que l'on pourrait vouloir maintenir, si vous désirez les capacités d'enregistrement (représentation mémoire compacte, par exemple).

(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)))
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top