在 cond-> 中分离哈希映射向量中的键

dissoc a key in a vector of hashmaps in a cond->

如何删除 cond-> 中的 :z of data ?

(def data
  {:a [{:x 1
        :y 2
        :z "remove this"}
       {:x 3
        :y 4
        :z 5}]
   :b "b"
   :c "c"})

我怀疑我必须使用更新,但我一直没有成功。

(cond-> data
        :a (#(<function to remove :z when :z is "remove this">))
        :b (dissoc :b))

我目前的理论是使用更新、映射和 if 语句。不过,我一直无法找到有效的确切语法

(cond-> data
        :a (#(update-in (:a %) [:z]
                        (map (fn [A]
                               (if (= (:z A) "remove this")
                                 (dissoc A :z)
                                 A))
                             (:a %))))
        :b (dissoc :b))
=> ClassCastException clojure.lang.LazySeq cannot be cast to clojure.lang.IFn  clojure.core/apply (core.clj:652) 

您的尝试非常接近:

您似乎确实两次导航“进入”地图。如果你想改变那个地图中:a的项目,那么update就足够了。此外,您不必通过 :z 路径,因为这是您想要从地图 dissoc 路径。

所以我的建议是:

(cond-> data
  :a (update :a
             (partial mapv #(if (= (:z %) "remove this") (dissoc % :z) %)))
  :b (dissoc :b))
  • update因为我们只改变顶层
  • 记住,update 的第一个参数来自 cond->
  • mapv保持向量
  • 传递给 update 的函数的第一个参数将是 (:a data),但是 mapv 将其作为最后一个参数 - 所以在这里使用 partial
  • 这让我们可以选择使用函数文字作为映射函数(记住,没有函数文字的嵌套);当然这个函数是一个候选提取到它自己的函数

也许您还想看看 specter:

(require '[com.rpl.specter :refer [ALL NONE setval]])

(cond->> data
  :a (setval [:a ALL :z #{"remove this"}] NONE)
  :b (setval :b NONE))

;;=> {:a [{:x 1, :y 2} {:x 3, :y 4, :z 5}], :c "c"}

我会稍微分解一个问题,所以你分阶段处理数据。使用我的 favorite template project,我们得到以下内容:

(ns tst.demo.core
  (:use tupelo.core tupelo.test))

(dotest
  (let [data   {:a [{:x 1
                     :y 2
                     :z "remove this"}
                    {:x 3
                     :y 4
                     :z 5}]
                :b "b"
                :c "c"}
        result (update data :a
                 (fn [vec-of-maps]
                   (mapv #(dissoc % :z) vec-of-maps)))]
    (is= result
      {:a [{:x 1 :y 2}
           {:x 3 :y 4}]
       :b "b"
       :c "c"})))

如果需要,您可以单独 dissoc :b