I'm trying to find matching key and value pairs from a map. I'm using the following code:
(defn matches? [m k v]
(let [val (k m)]
(= val v)))
my-demo.core=> (matches? {:a 1 :b 2} :b 2)
true
my-demo.core=> (matches? {:a 1 :b 2} :b 3)
false
Another approach using superset?
:
my-demo.core=> (superset? #{:a 1 :b 3} #{:a 1})
true
my-demo.core=> (superset? #{:a 1 :b 3} #{:a 2})
false
I have a feeling there is a better way to do this.
My question is: Is there an idiomatic way to find matching key and value in map in Clojure?
This is probably a small enough problem that you could just use this instead of defining a function:
(= ({:a 1 :b 2} :a)
1)
=> true
I would say this is an idiomatic way, which will work fine for most use cases.
However, it depends on the behaviour you require when testing for a nil
value. because the above method would return true
for :c nil
:
(= ({:a 1 :b 2} :c)
nil)
=> true
And your function behaves the same way:
(matches? {:a 1 :b 2} :c nil)
=> true
To get around this you could use get
with a "not found" value:
(= (get {:a 1 :b 2} :c ::not-found)
nil)
=> false
This works fine but it's perhaps not as neat. You'd just have to make sure that your "not found" value was never the same as your test value.
If you wanted to really know that a map contains a key with a possibly nil
value you would instead have to check both things. Here's a function that would do this while only doing the hash-map lookup once. It uses (find map key)
which returns the map entry (the key-value pair) for key, or nil if the key is not present.
(defn contains-kv? [m k v]
(if-let [kv (find m k)]
(= (val kv) v)
false))
(contains-kv? {:a 1 :b nil} :a 1)
=> true
(contains-kv? {:a 1 :b nil} :b nil)
=> true
(contains-kv? {:a 1 :b nil} :c nil)
=> false
Note: I don't think superset?
is doing what you think it does. In that example you're using sets, not hash maps, which are completely different:
(clojure.set/superset? #{:a 1 :b 2} #{:a :b})
=> true
Your matches?
function looks good to me, though I'd probably remove the let in this case, as it removes a bit of clutter. I'd also rename it to something more precise, though this is the best I can come up with just now:
(defn contains-kv?
"Returns true if the key k is present in the given map m and it's value matches v."
[m k v]
(= (m k) v))
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.