Frage

Ich möchte eine Karte der Werte mit denselben Tasten in eine andere Karte umwandeln, jedoch mit einer auf die Werte angewendeten Funktion. Ich würde denken, es gab eine Funktion dafür in der Clojure -API, aber ich konnte sie nicht finden.

Hier ist eine Beispielimplementierung dessen, wonach ich suche

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

Weiß jemand, ob map-function-on-map-vals ist bereits vorhanden? Ich würde denken, es tat (wahrscheinlich auch mit einem schöneren Namen).

War es hilfreich?

Lösung

Ich mag deine reduce Version gut. Ich denke, es ist idiomatisch. Hier ist eine Version, die das Listenverständnis sowieso verwendet.

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

Andere Tipps

Du kannst den ... benutzen 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}

Hier ist eine ziemlich typische Möglichkeit, eine Karte zu transformieren. zipmap Nimmt eine Liste von Schlüsseln und eine Liste von Werten und "das Richtige", die eine neue Clojure -Karte erzeugt. Sie könnten das auch setzen map um die Schlüssel, um sie oder beides zu ändern.

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

oder um es in Ihre Funktion einzuwickeln:

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

Aus dem Clojure-Kochbuch entnommen, gibt es record-kV:

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

Hier ist eine ziemlich idiomatische Art, dies zu tun:

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

Beispiel:

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

map-map, map-map-keys, und map-map-values

Ich kenne dafür keine vorhandene Funktion in Clojure, aber hier ist eine Implementierung dieser Funktion als map-map-values dass Sie frei zu kopieren sind. Es kommt mit zwei eng verwandten Funktionen, map-map und map-map-keys, die auch in der Standardbibliothek fehlen:

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

Verwendungszweck

Du kannst anrufen map-map-values so was:

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

Und die anderen beiden Funktionen wie diese:

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

Wenn Sie nur wollen map-map-keys oder map-map-values, ohne die allgemeineren map-map Funktion können Sie diese Implementierungen verwenden, auf die sich nicht verlassen 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)} )))

Hier ist auch eine alternative Implementierung von map-map das basiert auf clojure.walk/walk Anstatt von into, Wenn Sie diese Phrasierung bevorzugen:

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

Parellenversionen - pmap-map, etc.

Es gibt auch parallele Versionen dieser Funktionen, wenn Sie sie benötigen. Sie benutzen einfach pmap Anstatt von 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) )

Ich bin ein Clojure N00B, daher gibt es möglicherweise viel elegantere Lösungen. Hier ist meins:

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

Der Anon-Func macht eine kleine 2-Liste von jedem Schlüssel und seinem Wert. MAPCAT führt diese Funktion über die Abfolge der Tasten der Karte aus und verkettet die gesamte Arbeit zu einer großen Liste. "anwenden hash-map" erstellt eine neue Karte aus dieser Sequenz. Das (% m) sieht vielleicht etwas seltsam aus, es ist idiomatische Klosel, um einen Schlüssel auf eine Karte anzuwenden, um den zugehörigen Wert zu suchen.

Am dringend empfohlenes Lesen: die Clojure -Cheat -Blatt .

Ich mag deine reduce Ausführung. Mit einer sehr geringen Variation kann es auch die Art der Datensätze behalten:

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

Das {} wurde durch m. Mit dieser Änderung bleiben Aufzeichnungen auf Aufzeichnungen:

(defrecord Person [firstname lastname])

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

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

Durch anfangen mit {}, die Aufzeichnung verliert seine Aufzeichnung, welches vielleicht beibehalten möchte, wenn Sie die Datensatzfunktionen wünschen (beispielsweise kompakte Speicherdarstellung).

(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)))
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top