Clojure:将哈希映射关键字符串转换为关键字?

dMi*_*Mix 33 clojure

我正在使用Aleph从Redis中提取数据:

(apply hash-map @(@r [:hgetall (key-medication id)]))
Run Code Online (Sandbox Code Playgroud)

问题是这些数据带有键的字符串,例如:

({"name" "Tylenol", "how" "instructions"})
Run Code Online (Sandbox Code Playgroud)

当我需要它时:

({:name"Tylenol",:"指示"})

我之前通过以下方式创建了新地图:

{:name(m"name"),:how(m"how")}

但是对于大量密钥来说这是低效的.

如果有这样的功能吗?或者我必须遍历每个?

djh*_*rld 79

您还可以使用该clojure.walk库通过该功能获得所需的结果keywordize-keys

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

这将以递归方式遍历地图,因此它也将在嵌套地图中"关键字化"键

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

  • 它对我来说似乎不适用于嵌套映射. (2认同)

mik*_*era 43

有一个方便的函数叫关键字,它将字符串转换为适当的关键字:

(keyword "foo")
=> :foo
Run Code Online (Sandbox Code Playgroud)

因此,这只是使用此函数转换地图中所有键的情况.

我可能会使用带有解构的列表理解来执行此操作,例如:

(into {} 
  (for [[k v] my-map] 
    [(keyword k) v]))
Run Code Online (Sandbox Code Playgroud)

  • 有一个标准函数(在核心库中)将执行它,请参阅下面的答案 (3认同)

vie*_*bel 6

您可以使用以下方法非常优雅地实现此目的zipmap

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

基本上,zipmap允许通过分别指定键和值来创建映射。

  • 键和值是否保证顺序相同? (4认同)

nra*_*ako 6

也许值得注意的是,如果传入的数据是json并且您正在使用clojure.data.json,则可以指定 akey-fn和 avalue-fn来操作解析字符串的结果(文档) -

;; 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}
Run Code Online (Sandbox Code Playgroud)


Mat*_*W-D 5

我同意djhworld,clojure.walk/keywordize-keys是你想要的.

值得查看以下源代码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)))
Run Code Online (Sandbox Code Playgroud)

对于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)))
Run Code Online (Sandbox Code Playgroud)