Clojure 从深度嵌套贴图中删除nil值

Clojure 从深度嵌套贴图中删除nil值,clojure,Clojure,根据这张地图: {:a nil :b {:c nil :d 2 :e {:f nil :g 4}}} 我需要一个函数来删除所有的nil值,以便返回的映射是 {:b {:e {:g 4} :d 2}} 或者,如果给出: {:a nil :b {:c nil :d nil :e {:f nil :g nil}}} 结果是: nil 有一个答案,其中包含一个

根据这张地图:

{:a nil 
   :b {:c nil 
       :d 2 
       :e {:f nil 
           :g 4}}}
我需要一个函数来删除所有的nil值,以便返回的映射是

{:b {:e {:g 4}
     :d 2}}
或者,如果给出:

{:a nil 
   :b {:c nil 
       :d nil 
       :e {:f nil 
           :g nil}}}
结果是:

nil

有一个答案,其中包含一个假定适用于嵌套映射的函数,但当给定一个嵌套深度超过一级的映射时,该函数将失败。

从此处修改答案


使用specter,您可以这样做:

(declarepath DEEP-MAP-VALS)
(providepath DEEP-MAP-VALS (if-path map? [(compact MAP-VALS) DEEP-MAP-VALS] STAY))

(setval [DEEP-MAP-VALS nil?] NONE  
{:a nil 
  :b {:c nil 
      :d 2 
      :e {:f nil 
      :g 4}}})
请注意,如果没有剩余内容,它将返回
:com.rpl.specter.impl/NONE
,而不是
nil


这是对答案的部分重用,您可以通过
(remove(comp nil?second)el)
更改
(filter#(second%)el)
来处理
false
值,例如
{:a nil:b false}
将返回
{:b false}
@AbbéRésina,如果
nil
值很少,修改地图比重建地图更快:
(让[m(应用dissoc el(地图优先(过滤(comp-nil?second)el))))…)
感谢您的更正和建议。我已修复代码,只删除无值映射项。这不会保留记录,除非您使用
(and(not(record?el))(map?el))
。当然,然后您接受不会删除记录的nil值。
(defn clean [m]
  (if (map? m)
    (let [clean-val (fn [[k v]]
                      (let [v' (clean v)]
                        (when-not (nil? v')
                          [k v'])))
          m' (->> (map clean-val m)
                  (remove nil?)
                  (into {}))]
      (when-not (empty? m') m'))
    m))
(declarepath DEEP-MAP-VALS)
(providepath DEEP-MAP-VALS (if-path map? [(compact MAP-VALS) DEEP-MAP-VALS] STAY))

(setval [DEEP-MAP-VALS nil?] NONE  
{:a nil 
  :b {:c nil 
      :d 2 
      :e {:f nil 
      :g 4}}})