tutorial online example clojure

online - clojure vs scala



Clojure: ¿Convertir cadenas de claves hash en palabras clave? (6)

Estoy de acuerdo con djhworld, clojure.walk/keywordize-keys es lo que quieres.

Vale la pena echar un vistazo al código fuente de clojure.walk/keywordize-keys :

(defn keywordize-keys "Recursively transforms all map keys from strings to keywords." [m] (let [f (fn [[k v]] (if (string? k) [(keyword k) v] [k v]))] (clojure.walk/postwalk (fn [x] (if (map? x) (into {} (map f x)) x)) m)))

La transformación inversa a veces es útil para la interoperabilidad de Java:

(defn stringify-keys "Recursively transforms all map keys from keywords to strings." [m] (let [f (fn [[k v]] (if (keyword? k) [(name k) v] [k v]))] (clojure.walk/postwalk (fn [x] (if (map? x) (into {} (map f x)) x)) m)))

Estoy extrayendo datos de Redis usando Aleph:

(apply hash-map @(@r [:hgetall (key-medication id)]))

El problema es que estos datos regresan con cadenas de claves, por ejemplo:

({"name" "Tylenol", "how" "instructions"})

Cuando necesito que sea:

({: nombre "Tylenol",: cómo "instrucciones")

Anteriormente estaba creando un nuevo mapa a través de:

{: nombre (m "nombre"),: cómo (m "cómo")}

Pero esto es ineficiente para una gran cantidad de claves.

Si hay una función que hace esto? ¿O tengo que pasar por cada uno?


Hay una función práctica llamada keyword que convierte cadenas en las palabras clave apropiadas:

(keyword "foo") => :foo

Por lo tanto, solo se trata de transformar todas las claves de su mapa con esta función.

Probablemente usaría una lista de comprensión con desestructuración para hacer esto, algo así como:

(into {} (for [[k v] my-map] [(keyword k) v]))


Puedes lograr esto muy elegantemente usando zipmap :

(defn modify-keys [f m] (zipmap (map f (keys m)) (vals m))) (modify-keys keyword {"name" "Tylenol", "how" "instructions"}) ; {:how "instructions", :name "Tylenol"}

Básicamente, zipmap permite crear un mapa especificando claves y valores por separado.


Quizás vale la pena señalar que, si los datos entrantes son json y está utilizando clojure.data.json , puede especificar tanto una key-fn como un value-fn para manipular resultados al analizar la cadena ( docs ) -

;; Examples from the docs (ns example (:require [clojure.data.json :as json])) (json/read-str "{/"a/":1,/"b/":2}" :key-fn keyword) ;;=> {:a 1, :b 2} (json/read-str "{/"a/":1,/"b/":2}" :key-fn #(keyword "com.example" %)) ;;=> {:com.example/a 1, :com.example/b 2}


También puede usar la biblioteca clojure.walk para lograr el resultado deseado con la función keywordize-keys

(use ''clojure.walk) (keywordize-keys {"name" "Tylenol", "how" "instructions"}) ;=> {:name "Tylenol", :how "instructions"}

Esto recorrerá el mapa recursivamente también para que también "clave" las palabras clave en el mapa anidado

http://clojuredocs.org/clojure_core/clojure.walk/keywordize-keys


Yo segundo @ mikera into respuesta basada . Alternativamente, no es la más concisa pero, otra opción que usa assoc + dissoc / reduce sería:

(reduce #(dissoc (assoc %1 (keyword %2) (get %1 %2)) %2) my-map (keys may-map))