【问题标题】:How to write a dissoc-in command for clojure?如何为clojure编写dissoc-in命令?
【发布时间】:2013-01-07 10:19:33
【问题描述】:

我正在寻找与 assoc-in 类似但删除键而不是添加键的函数:

(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 {}}}

但是整个嵌套的东西让我头疼

【问题讨论】:

标签: clojure


【解决方案1】:

我用 update-in 写这个:

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

=>

{:a {:c 1}}

【讨论】:

  • 不错的解决方案。请注意,路径长度为 1 需要特殊情况。 ``` (defn dissoc-in "返回嵌套散列并删除路径" [m ks] (let [path (butlast ks) node (last ks)] (if (empty?path) (dissoc m node) (update-in m 路径 dissoc 节点)))) ```
【解决方案2】:

怎么样:

(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])

结果:

{:a {:c 1}}

dissoc-in 曾经是clojure.contrib.core 的一部分,现在是core.incubator 的一部分。


如果你想保留空地图,你可以稍微修改一下代码:

(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 {:c 0}}} [:a :b])

结果:

{:a {}}

【讨论】:

  • 确实,空地图是否应该被删除,人们有自己的偏好,这个正在讨论中。到目前为止,在我的用例中,我选择了删除空映射的原始 clojure.contrib.core 代码(上面由 Dominic 引用)。
  • 文档位于:github.com/clojure/core.incubator 当前 lein 坐标为 [org.clojure/core.incubator "0.1.3"]。在你的要求中使用类似“[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))
【解决方案3】:

这是一个基于update-in的通用解决方案:

(defn dissoc-in [m p]
  (if (get-in m p) 
    (update-in m
               (take (dec (count p)) p)
               dissoc (last p))
    m))

【讨论】:

  • 可以使用(drop-last p) 代替(take...)。 (或butlast,但可能不鼓励这样做。)
【解决方案4】:

受到 Dominic 的代码的启发。我写了一个更简洁的版本

(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]) 
;;=> {}    

【讨论】:

    【解决方案5】:

    不用写了,clojure.core.incubator已经有dissoc-in了:

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

    【讨论】:

      【解决方案6】:

      我建议使用medley library 中的dissoc-in

      这是 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))
      

      这是link to the source code of dissoc-in in medley master

      【讨论】:

        【解决方案7】:
        (defn dissoc-in [m ks]
          (let [parent-path (butlast ks)
                leaf-key (last ks)]
            (if (= (count ks) 1)
              (dissoc m leaf-key)
              (update-in m parent-path dissoc leaf-key))))
        

        【讨论】:

        • 虽然这段代码 sn-p 可以解决问题,including an explanation 确实有助于提高您的帖子质量。请记住,您是在为将来的读者回答问题,而这些人可能不知道您提出代码建议的原因。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-10
        • 2016-07-08
        • 1970-01-01
        相关资源
        最近更新 更多