如何在clojure的命令中编写dissoc?
我希望编写一个类似于中的assoc的函数,但删除键而不是添加键:如何在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
(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节点中更新)))```