更改集合中的所有关键字,从命名空间中删除点并用短划线替换

时间:2016-04-19 15:51:57

标签: clojure

如何在地图矢量(也包含地图矢量)上映射函数以从关键字命名空间中删除所有点?

所以,给定:

[{: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"}]}]

3 个答案:

答案 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"}]}]