合并地图,但有些值为零

merging maps, but some values are nil

所以我有两个地图,可以是任何东西,我想合并它们,但不包括 nil 值。 假设我有:

(def x {:a "A" :c 5 :d "D"})
(def y {:a 1 :b 2 :c nil})

我想结束

{:a 1 :b 2 :c 5 :d "D"}

如果我只是像 (merge x y) 那样合并,我会得到错误的 :c 值,但是 {:c nil} 在那里。我无法控制哪两张地图进来。任何帮助将不胜感激

您可以像这样轻松删除包含 nil 的地图条目:

(ns tst.demo.core
  (:use tupelo.core tupelo.test)
  (:require
    [schema.core :as s]
  ))

(defn remove-nil-vals
  [m]
  (into {}
        (for [[k v] m
              :when (not (nil? v))]
          [k v])))

(dotest
  (let [x              {:a "A" :c 5 :d "D"}
        y              {:a 1 :b 2 :c nil}
        all-maps       [x y]
        merged-no-nils (into {}
                             (for [m all-maps]
                               (remove-nil-vals m)))]

    (is= (remove-nil-vals x)  {:a "A" :c 5 :d "D"})
    (is= (remove-nil-vals y)  {:a 1 :b 2})
    (is= merged-no-nils       {:a 1 :c 5 :d "D" :b 2})

  ))

以上是根据this template project.

如果您想以不让 nil 值覆盖非 nil 值的方式合并哈希映射,您可以使用 merge-with:

dev=> (def x {:a "A" :c 5 :d "D"})
#'dev/x
dev=> (def y {:a 1 :b 2 :c nil})
#'dev/y
dev=> (merge-with (fn [a b] (if (some? b) b a)) x y)
{:a 1, :c 5, :d "D", :b 2}
dev=> 

some? returns true 如果它的参数是任何非 nil 值。

使用 into with the second argument being a filtering transducer 会生成一段相当简洁且可读性强的代码:

(def x {:a "A" :c 5 :d "D"})
(def y {:a 1 :b 2 :c nil})

(into x (filter (comp some? val)) y)
;; => {:a 1, :c 5, :d "D", :b 2}

如果您需要的话,只需要稍作调整即可从 first 映射中删除 nils:

(def x {:a "A" :c 5 :d "D" :e nil :f nil})
(def y {:a 1 :b 2 :c nil})

(into {} (comp cat (filter (comp some? val))) [x y])
;; => {:a 1, :c 5, :d "D", :b 2}