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

发布于 2025-01-08 01:33:25 字数 449 浏览 1 评论 0原文

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

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

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

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

当我需要它时:

({:name "Tylenol", :how "说明})

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

{ :name (m "名字"), :how (m "如何")}

但这对于大量的键来说效率很低。

如果有一个函数可以做到这一点?或者我必须循环遍历每个?

I'm pulling data from Redis using Aleph:

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

The problem is this data comes back with strings for keys, for ex:

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

When I need it to be:

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

I was previously creating a new map via:

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

But this is inefficient for a large amount of keys.

If there a function that does this? Or do I have to loop through each?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

最好是你 2025-01-15 01:33:25

您还可以使用 clojure.walk 库通过函数 keywordize-keys 来实现所需的结果,

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

这也会递归地遍历映射,因此它将“关键字化”中的键也有嵌套映射

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

You can also use the clojure.walk library to achieve the desired result with the function keywordize-keys

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

This will walk the map recursively as well so it will "keywordize" keys in nested map too

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

甜心小果奶 2025-01-15 01:33:25

有一个名为 keyword 的方便函数,可以将字符串转换为适当的关键字:

(keyword "foo")
=> :foo

所以它只是一个使用此函数转换地图中所有键的情况。

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

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

There is a handy function called keyword that converts Strings into the appropriate keywords:

(keyword "foo")
=> :foo

So it's just a case of transforming all the keys in your map using this function.

I'd probably use a list comprehension with destructuring to do this, something like:

(into {} 
  (for [[k v] my-map] 
    [(keyword k) v]))
酒绊 2025-01-15 01:33:25

我同意 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)))

逆变换有时对于 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)))

I agree with djhworld, clojure.walk/keywordize-keys is what you want.

It's worth peeking at the source code of 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)))

The inverse transform is sometimes handy for 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)))
帅冕 2025-01-15 01:33:25

也许值得注意的是,如果传入的数据是 json 并且您使用的是 clojure.data.json,则可以指定 key-fn code> 和一个 value-fn 用于操作解析字符串的结果(docs< /a>) -

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

Perhaps it is worth noting that, if the incoming data is json and you are using clojure.data.json, you can specify both a key-fn and a value-fn for manipulating results on parsing the string (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}
情何以堪。 2025-01-15 01:33:25

您可以使用 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 允许通过分别指定键和值来创建映射。

You can achieve this very elegantly using zipmap:

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

Basically, zipmap allows to create a map by specifying keys and values separately.

九八野马 2025-01-15 01:33:25

使用keyword函数和reduce-kv

如果我有地图,例如

 (def test-map {"key1" "val1" "key2" "val2"}

我可以做

(reduce-kv 
     (fn [m k v] 
        (assoc m (keyword k) v)) 
      {} test-map)

 => {:key1 "val1" :key2 "val2"}

Using the keyword function and reduce-kv.

If I have a map e.g.

 (def test-map {"key1" "val1" "key2" "val2"}

I can do

(reduce-kv 
     (fn [m k v] 
        (assoc m (keyword k) v)) 
      {} test-map)

 => {:key1 "val1" :key2 "val2"}
撞了怀 2025-01-15 01:33:25

我赞同 @mikera 的基于的答案。或者,不是最简洁的,而是使用 assoc+dissoc/reduce 的另一个选项是:

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

I second @mikera's into based answer. Alternatively, not the most concise but, another option using assoc+dissoc/reduce would be:

(reduce #(dissoc (assoc %1 (keyword %2) (get %1 %2)) %2) my-map (keys may-map))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文