如何在clojure的命令中编写dissoc?

如何在clojure的命令中编写dissoc?,clojure,Clojure,我希望编写一个类似于中的assoc的函数,但删除键而不是添加键: (dissoc-in {:a {:b 0}} [:a :b]) ;;=> {:a {}} 我来到这里: (def m {:a {:b {:c 1}}}) (assoc m :a (assoc (:a m) :b (dissoc (:b (:a m)) :c))) ;;=> {:a {:b {}}} 但是整个嵌套的东西都在搅乱我的脑袋怎么样: (defn dissoc-in "Dissociates an e

我希望编写一个类似于中的assoc的函数,但删除键而不是添加键:

(dissoc-in {:a {:b 0}} [:a :b])
;;=> {:a {}}
我来到这里:

(def m {:a {:b {:c 1}}})

(assoc  m :a (assoc (:a m) :b (dissoc (:b (:a m)) :c)))
;;=> {:a {:b {}}}
但是整个嵌套的东西都在搅乱我的脑袋

怎么样:

(defn dissoc-in
  "Dissociates an entry from a nested associative structure returning a new
  nested structure. keys is a sequence of keys. Any empty maps that result
  will not be present in the new structure."
  [m [k & ks :as keys]]
  (if ks
    (if-let [nextmap (get m k)]
      (let [newmap (dissoc-in nextmap ks)]
        (if (seq newmap)
          (assoc m k newmap)
          (dissoc m k)))
      m)
    (dissoc m k)))
例如:

(dissoc-in {:a {:b 0 :c 1}} [:a :b])
(dissoc-in {:a {:b {:c 0}}} [:a :b])
结果:

{:a {:c 1}}
{:a {}}
dissoc in
曾经是的一部分,现在是的一部分


如果要保留空映射,可以稍微修改代码:

(defn dissoc-in
  [m [k & ks :as keys]]
  (if ks
    (if-let [nextmap (get m k)]
      (let [newmap (dissoc-in nextmap ks)]
        (assoc m k newmap))
      m)
    (dissoc m k)))
例如:

(dissoc-in {:a {:b 0 :c 1}} [:a :b])
(dissoc-in {:a {:b {:c 0}}} [:a :b])
结果:

{:a {:c 1}}
{:a {}}

受到多米尼克密码的启发。我写了一个更简洁的版本

(defn dissoc-in
  [m [k & ks]]
  (if-not ks
    (dissoc m k)
    (assoc m k (dissoc-in (m k) ks))))

(dissoc-in {:a {:b {:c 1}}} [:a :b :c])  ;; => {:a {:b {}}}
另一个版本dissoc-in2递归删除空映射

(defn dissoc-in2
  [m [k & ks]]
  (if-not ks
    (dissoc m k)
    (let [nm (dissoc-in2 (m k) ks)]
      (cond (empty? nm) (dissoc m k)
            :else (assoc m k nm)))))


(ut/dissoc-in {:a {:b {:c 3}}} [:a :b :c]) 
;;; => {:a {:b {}}}

(ut/dissoc-in2 {:a {:b {:c 3}}} [:a :b :c]) 
;;=> {}    

我在中使用更新来写这篇文章:

(update-in {:a {:b 0 :c 1}} [:a] dissoc :b)
=>


以下是基于中更新的通用解决方案:

(defn dissoc-in [m p]
  (if (get-in m p) 
    (update-in m
               (take (dec (count p)) p)
               dissoc (last p))
    m))
无需编写,在中已经有一个dissoc:

=> (dissoc-in {:children [{:name "Billy" :age 5}]} [:children 0 :age])
{:children [{:name "Billy"}]}

我建议在中使用
dissoc

以下是0.7.0版的代码:

(defn dissoc-in
  "Dissociate a value in a nested assocative structure, identified by a sequence
  of keys. Any collections left empty by the operation will be dissociated from
  their containing structures."
  [m ks]
  (if-let [[k & ks] (seq ks)]
    (if (seq ks)
      (let [v (dissoc-in (get m k) ks)]
        (if (empty? v)
          (dissoc m k)
          (assoc m k v)))
      (dissoc m k))
    m))

这是一个。

事实上,人们对是否删除空地图有自己的偏好,这一点正在讨论中。到目前为止,在我的用例中,我选择了原始的clojure.contrib.core代码(上面由Dominic引用),它删除了空映射)。文档位于:Current lein coords are[org.clojure/core.incubator“0.1.3”]。在您的require中使用类似“[clojure.core.incubator:as cci]”的东西,然后在程序中:(cci/dissoc In{:a{:aa 1}:b{:bb 2}}[:a:aa])生成{:b{:bb 2}@0dB我刚刚遇到了一个由删除空映射引起的错误。其中一个映射是优先级映射,而不是常规映射,所以您可以想象我稍后尝试使用它时发生了什么。(>some map(dissoc in[:prio map 123])(assoc in[:prio map 234]something))可以使用
(drop last p)
而不是
(take…)
。(或
butlast
,但可能不鼓励这样做。)请参阅2012年9月创建的“虽然有assoc-in,但没有clojure.core/dissoc-in”。虽然此代码片段可以解决问题,但确实有助于提高您文章的质量。请记住,您将在将来回答读者的问题,而这些人可能不知道您的代码建议的原因。这是一个很好的解决方案。请注意,路径长度为1时需要特殊情况(在“返回已删除路径的嵌套哈希”中定义dissoc“[m ks](让[path(butlast ks)节点(last ks)](if(empty?path)(dissoc m node)(在m path dissoc节点中更新)))```