I'm new to Clojure and I was wondering if there was a way to test if a map has multiple keys. I've noticed that contains?
only checks for one key
What i'm trying to do:
(def mario
{:position {:x 1 :y 2}
:velocity {:x 2 :y 0}
:mass 20})
;;Test if mario has a position and a velocity
(contains-many? mario :position :velocity) ;;true
;;Test if mario has a mass and a jump-height
(contains-many? mario :mass :jump-height) ;;false
basically, is there a function like contains-many?
in the clojure library and if not how would you implement the contains-many?
function?
The correct answer was shown, but I would like to point out another elegant solution which assums knowledge about the map values. When you know for sure they are truthy (that is: not nil
and not false
):
(every? m ks)
This is due to the fact that maps are (unary) functions which return the corresponding value to the argument. But note that ({:x nil} :x) => nil
.
I don't know any function that does that. It is also necessary to define whether you want the map to contain every key or just some keys. I chose the every case, if you wanted the some version, just replace every?
with some?
.
My direct, not optimized, version is:
(defn contains-many? [m & ks]
(every? #(contains? m %) ks))
Which has been tested with:
(deftest a-test
(testing "Basic test cases"
(let [m {:a 1 :b 1 :c 2}]
(is (contains-many? m :a))
(is (contains-many? m :a :b))
(is (contains-many? m :a :b :c))
(is (not (contains-many? m :a :d)))
(is (not (contains-many? m :a :b :d))))))
Edit: Simplified using noisesmith's suggestion
You could leverage clojure.set/subset?
(clojure.set/subset?
#{:position :velocity}
(set (keys mario)))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With