Je tire des données de Redis en utilisant Aleph:
(apply hash-map @(@r [:hgetall (key-medication id)]))
Le problème est que ces données sont renvoyées avec des chaînes pour les clés, par exemple:
({"name" "Tylenol", "how" "instructions"})
Quand j'en ai besoin pour être:
({: name "Tylenol",: comment "instructions})
J'étais en train de créer une nouvelle carte via:
{: nom (m "nom"),: comment (m "comment")}
Mais ceci est inefficace pour une grande quantité de clés.
S'il y a une fonction qui fait ça? Ou dois-je les parcourir en boucle?
Il existe une fonction pratique appelée mot clé qui convertit les chaînes en mots clés appropriés:
(keyword "foo")
=> :foo
Il ne s'agit donc que de transformer toutes les clés de votre carte à l'aide de cette fonction.
Pour ce faire, j'utiliserais probablement une compréhension de liste avec déstructuration, par exemple:
(into {}
(for [[k v] my-map]
[(keyword k) v]))
Vous pouvez également utiliser la bibliothèque clojure.walk
pour obtenir le résultat souhaité avec la fonction keywordize-keys
.
(use 'clojure.walk)
(keywordize-keys {"name" "Tylenol", "how" "instructions"})
;=> {:name "Tylenol", :how "instructions"}
Cela permettra également de parcourir la carte de manière récursive, de sorte que les clés de la carte imbriquée seront également "mot-clé".
http://clojuredocs.org/clojure_core/clojure.walk/keywordize-keys
Je suis d'accord avec djhworld, clojure.walk/keywordize-keys
est ce que vous voulez.
Cela vaut la peine de jeter un coup d'œil au code source 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 transformation inverse est parfois utile pour Java interop:
(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)))
Vous pouvez y parvenir très élégamment en utilisant zipmap
:
(defn modify-keys [f m] (zipmap (map f (keys m)) (vals m)))
(modify-keys keyword {"name" "Tylenol", "how" "instructions"})
; {:how "instructions", :name "Tylenol"}
zipmap
permet de créer une carte en spécifiant les clés et les valeurs séparément.
Il convient peut-être de noter que, si les données entrantes sont json
et que vous utilisez clojure.data.json
, vous pouvez spécifier un key-fn
et un value-fn
pour manipuler les résultats lors de l'analyse syntaxique de la chaîne ( 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}
Je partage la réponse into
de @ mikera. Alternativement, pas la plus concise, mais une autre option utilisant assoc + dissoc/reduction serait:
(reduce #(dissoc (assoc %1 (keyword %2) (get %1 %2)) %2) my-map (keys may-map))