有没有一种惯用的方法可以在Clojure中的map中找到匹配的键和值



我正试图从映射中找到匹配的键值对。我使用以下代码:

(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

使用superset?:的另一种方法

my-demo.core=> (superset? #{:a 1 :b 3} #{:a 1})
true
my-demo.core=> (superset? #{:a 1 :b 3} #{:a 2})
false

我觉得有更好的方法可以做到这一点。

我的问题是:有没有一种惯用的方法可以在Clojure中的映射中找到匹配的键和值

这可能是一个足够小的问题,您可以使用它而不是定义一个函数:

(= ({:a 1 :b 2} :a)
   1)
=> true

我认为这是一种惯用的方式,适用于大多数用例。


但是,这取决于测试nil值时所需的行为。因为上述方法将针对:c nil:返回true

(= ({:a 1 :b 2} :c)
   nil)
=> true

你的功能也有同样的表现:

(matches? {:a 1 :b 2} :c nil)
=> true

为了解决这个问题,您可以使用具有"未找到"值的get

(= (get {:a 1 :b 2} :c ::not-found)
   nil)
=> false

这很好用,但可能不那么整洁。你只需要确保你的"未找到"值永远不会和你的测试值相同。


如果您真的想知道映射包含一个可能具有nil值的键,那么您必须同时检查这两件事。这里有一个函数,它可以在只执行一次哈希图查找的同时执行此操作。它使用(find map key),返回键的映射条目(键值对),如果键不存在,则返回nil。

(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

注意:我不认为superset?在做你认为它在做的事情。在这个例子中,你使用的是集合,而不是哈希图,这是完全不同的:

(clojure.set/superset? #{:a 1 :b 2} #{:a :b})
=> true

您的matches?函数对我来说很好,尽管在这种情况下我可能会删除let,因为它会删除一些混乱。我也会把它重命名为更精确的东西,尽管这是我现在能想到的最好的:

(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))

最新更新