Reputation: 19
So I have two maps that can be anything and I want to merge them, but not include values that are nil. Let's say I have:
(def x {:a "A" :c 5 :d "D"})
(def y {:a 1 :b 2 :c nil})
I want to end up with
{:a 1 :b 2 :c 5 :d "D"}
I get the wrong value for :c if I just merge like (merge x y), but {:c nil} is there. I do not have control over what two maps come in. Any help would be aappreciated
Upvotes: 1
Views: 503
Reputation: 41
A bit similar to what already Sean Corfield answered, but a little bit shorter:
(merge-with #(or %1 %2) x y)
Example:
user=> (def x {:a "A" :c 5 :d "D"})
#'user/x
user=> (def y {:a 1 :b 2 :c nil})
#'user/y
user=> (merge-with #(or %1 %2) x y)
{:a "A", :c 5, :d "D", :b 2}
Upvotes: 1
Reputation: 4901
Using into with the second argument being a filtering transducer results in a piece of code that is both fairly concise and readable:
(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}
Only minor tweaks are required to have it remove nils from the first map too, if you need that:
(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}
Upvotes: 5
Reputation: 6666
If you want to merge hash maps in a way that doesn't let nil
values override non-nil
values, you can use 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
if its argument is any non-nil
value.
Upvotes: 5
Reputation: 29958
You can easily remove map entries that contain a nil
like so:
(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})
))
The above is based on this template project.
Upvotes: -1