如何在地图矢量(也包含地图矢量)上映射函数以从关键字命名空间中删除所有点?
所以,给定:
[{:my.dotted/namespace "FOO"}
{:my.nested/vec [{:another.dotted/namespace "BAR"
:and.another/one "FIZ"}]}]
变为:
[{:my-dotted/namespace "FOO"}
{:my-nested/vec [{:another-dotted/namespace "BAR"
:and-another/one "FIZ"}]}]
答案 0 :(得分:6)
听起来像是clojure.walk的工作!
您可以遍历整个数据结构并将转换函数(我的版本中为transform-map
)应用于切换地图键(此处为dotted->dashed
)的所有子表单
(require '[clojure
[walk :as walk]
[string :as str]])
(defn remove-dots-from-keys
[data]
(let [dotted->dashed #(-> % str (str/replace "." "-") (subs 1) keyword)
transform-map (fn [form]
(if (map? form)
(reduce-kv (fn [acc k v] (assoc acc (dotted->dashed k) v)) {} form)
form))]
(walk/postwalk transform-map data)))
答案 1 :(得分:2)
对于这类工作,我偏向clojure.walk
。基本思想是创建函数,如果给定应该替换的值,则执行所需的替换,否则返回参数。然后将该函数和结构交给postwalk
(或prewalk
),它会为您遍历数据结构,将每个值替换为函数的返回值。
(ns replace-keywords
(:require [clojure.walk :refer [postwalk]]
[clojure.string :refer [join]]))
(defn dash-keyword [k]
(when (keyword? k)
(->> k
str
(map (some-fn {\. \-} identity))
rest
join
keyword)))
(dash-keyword :foo.bar/baz)
;; => :foo-bar/baz
(defonce nested [ {:my-dotted/namespace "FOO"}
{:my-nested/vec [ {:another-dotted/namespace "BAR"
:and-another/one "FIZ"} ]}])
(postwalk (some-fn dash-keyword identity) nested)
;; =>[{:my-dotted/namespace "FOO"}
;; {:my-nested/vec [{:another-dotted/namespace "BAR",
;; :and-another/one "FIZ"}]}]
这里我两次使用some-fn
与返回替换或nil
的函数的组合,这可以很好地结合几个"替换规则" - 如果之前的任何一个都没有,那么identity
将是第一个返回非nil
值并且参数不会被更改的。
答案 2 :(得分:2)
如果没有clojure.walk
:
(require '[clojure.string :as str])
(defn dot->dash [maps]
(mapv #(into {} (for [[k v] %]
[(keyword (str/replace (namespace k) "." "-") (name k))
(if (vector? v) (dot->dash v) v)]))
maps))
示例:
(dot->dash [{:my.dotted/namespace "FOO"}
{:my.nested/vec [{:another.dotted/namespace "BAR"
:and.another/one "FIZ"}]}])
;=> [{:my-dotted/namespace "FOO"}
; {:my-nested/vec [{:another-dotted/namespace "BAR"
; :and-another/one "FIZ"}]}]