代码之家  ›  专栏  ›  技术社区  ›  edoloughlin

从地图中删除零值?

  •  25
  • edoloughlin  · 技术社区  · 14 年前

    例如。:

    (def record {:a 1 :b 2 :c nil})
    (merge (for [[k v] record :when (not (nil? v))] {k v}))
    

    这会产生一系列的映射,这不是我从merge中所期望的:

    ({:a 1} {:b 2})
    

    我想要:

    {:a 1, :b 2}
    
    9 回复  |  直到 14 年前
        1
  •  59
  •   Jürgen Hötzel    14 年前

    你的 list comprehension返回映射列表,因此需要将此列表作为可选参数应用于merge函数:

    user> (apply merge (for [[k v] record :when (not (nil? v))] {k v}))
    {:b 2, :a 1}      
    

    更简洁的解决方案是将地图作为一个序列进行过滤,并合并到地图中:

    user> (into {} (filter second record))
    {:a 1, :b 2}  
    

    不删除 价值观:

    user> (into {} (remove (comp nil? second) record))
    {:a 1, :b false}  
    

    使用 消散 要允许持久数据共享而不是创建一个全新的映射,请执行以下操作:

    user> (apply dissoc                                                                                            
           record                                                                                                  
           (for [[k v] record :when (nil? v)] k))
    {:a 1, :b 2}  
    
        2
  •  7
  •   Eelco    10 年前

    (defn remove-nils
      [m]
      (let [f (fn [[k v]] (when v [k v]))]
        (postwalk (fn [x] (if (map? x) (into {} (map f x)) x)) m)))
    
        3
  •  6
  •   Marklar    9 年前

    @Eelco回答的一个变体:

    (defn remove-nils [m]
      (let [f (fn [x]
                (if (map? x)
                  (let [kvs (filter (comp not nil? second) x)]
                    (if (empty? kvs) nil (into {} kvs)))
                  x))]
        (clojure.walk/postwalk f m)))
    

    对于@broma0的点,它忽略了任何空的地图。

    user> (def m {:a nil, :b 1, :c {:z 4, :y 5, :x nil}, :d {:w nil, :v nil}})
    user> (remove-nils m)
    {:b 1, :c {:z 4, :y 5}}
    user> (remove-nils {})
    nil
    
        4
  •  5
  •   thnetos    14 年前

    你可以把它压在地图上:

    (into {} (remove (fn [[k v]] (nil? v)) {:a 1 :b 2 :c nil}))
    => {:a 1 :b 2}
    
        5
  •  4
  •   Xavi    10 年前

    改进Jrgen Htzel解决方案以解决nil/false问题

    (into {} (filter #(not (nil? (val %))) {:a true :b false :c nil}))
    

    (into {} (remove #(nil? (val %)) {:a true :b false :c nil}))
    
        6
  •  2
  •   Christopher Maier    14 年前

    尽管Jrgen(filter second record)的方法得到了我对最漂亮的Clojure技巧的投票,但我想我会用另一种方法,这次使用 select-keys :

    user> (select-keys record (for [[k v] record :when (not (nil? v))] k))
    {:b 2, :a 1}
    
        7
  •  2
  •   Pardeep Singh    8 年前

    降低电压也可用于拔出钥匙

    (reduce-kv (fn [m key value]
                    (if (nil? value)
                      (dissoc m key)
                      m))
                {:test nil, :test1 "hello"}
                {:test nil, :test1 "hello"})
    
        8
  •  1
  •   Jonathan Tran    14 年前

    你可以使用reduce。

    user> (reduce (fn [m [k v]] (if (nil? v) m (assoc m k v))) {} record)
    {:b 2, :a 1}
    

    dissoc .

    user> (reduce (fn [m [k v]] (if (nil? v) (dissoc m k) m)) record record)
    {:a 1, :b 2}
    
        9
  •  1
  •   Noam Ben Ari    9 年前

    (defn compact
      [coll]
      (cond
        (vector? coll) (into [] (filter (complement nil?) coll))
        (map? coll) (into {} (filter (comp not nil? second) coll))))