关于选定关键字的Clojure烤肉串案例

时间:2017-04-07 15:45:22

标签: clojure

我想在clojure的大地图中更改某些键。 这些密钥可以出现在地图中的任何级别,但始终位于必需密钥

我正在考虑使用camel-snake-kebab库,但是需要它才能在必需键映射中仅更改给定的一组键。如果在json或地图中进行更改无关紧要

   (def my-map {:allow_kebab_or-snake {:required-key {:must_be_kebab ""}}
             :allow_kebab_or-snake2 {:optional-key {:required-key {:must_be_kebab ""}}}})

目前使用/ walk / postwalk-replace但担心它可能会更改未嵌套在:required-key map中的键

(walk/postwalk-replace {:must_be_kebab :must-be-kebab} my-map))

3 个答案:

答案 0 :(得分:0)

你可以澄清一下:你想改变地图的键吗?!或其相关值?

偏离主题:上面的地图不正确(有两个相同的键:allow_kebab_or_snake - 我假设你只是强调了这一点而没有显示实际的例子:))

postwalk-replace将用值替换任何出现的键。

所以,如果你知道确切的map结构,你可以先用get-in选择你的子结构,然后使用postwalk-replace:

(walk/postwalk-replace {:must_be_kebab :mus-be-kebab}
                       (get-in my-map [:allow_kebab_or_snake :required-key]))

但是你必须将assoc这个放入你的初始地图中。

如果交错DS过于复杂,您还应该考虑walk函数并构建自己的特定算法。

答案 1 :(得分:0)

这是一个解决方案。由于您需要控制转换何时执行/不执行,因此您不能只使用postwalk。您需要实现自己的递归并从非转换中更改上下文 - >找到你的病情后转换。

(ns tst.clj.core
  (:use clj.core clojure.test tupelo.test)
  (:require
    [clojure.string :as str]
    [clojure.pprint :refer [pprint]]
    [tupelo.core :as t]
    [tupelo.string :as ts]
  ))
(t/refer-tupelo)
(t/print-versions)

(def my-map
  {:allow_kebab_or-snake  {:required-key {:must_be_kebab ""}}
   :allow_kebab_or-snake2 {:optional-key {:required-key {:must_be_kebab ""}}}})

(defn children->kabob? [kw]
  (= kw :required-key))

(defn proc-child-maps
  [ctx map-arg]
  (apply t/glue
    (for [curr-key (keys map-arg)]
      (let [curr-val (grab curr-key map-arg)
            new-ctx  (if (children->kabob? curr-key)
                       (assoc ctx :snake->kabob true)
                       ctx)
            out-key  (if (grab :snake->kabob ctx)
                       (ts/kw-snake->kabob curr-key)
                       curr-key)
            out-val  (if (map? curr-val)
                       (proc-child-maps new-ctx curr-val)
                       curr-val)]
        {out-key out-val}))))

(defn nested-keys->snake
  [arg]
  (let [ctx {:snake->kabob false}]
    (if (map? arg)
      (proc-child-maps ctx arg)
      arg)))

最终结果显示在单元测试中:

  (is= (nested-keys->snake my-map)
    {:allow_kebab_or-snake
     {:required-key
      {:must-be-kebab ""}},
     :allow_kebab_or-snake2
     {:optional-key
      {:required-key
       {:must-be-kebab ""}}}} ))

对于这个解决方案,我使用了一些便利函数documentation

答案 2 :(得分:0)

只是左侧的字段建议,可能有效,也可能无效。这是在处理SQL数据库时可能出现的问题,因为' - '被视为保留字,不能在标识符中使用。但是,在使用clojure时,通常在关键字中使用“ - ”。在clojure中使用SQL时使用的许多抽象层将映射作为预处理语句等的参数/绑定。

理想情况下,需要的是另一层抽象,它根据你要去的方向(即sql或sql)根据需要在kebab和snake case之间进行转换。这种方法的优势在于您无需通过地图进行转换 - 您可以在需要时“即时”进行转换。

查看https://pupeno.com/2015/10/23/automatically-converting-case-between-sql-and-clojure/