在Clojure中有没有找到地图中匹配键和值的惯用方法?

时间:2015-02-07 04:57:16

标签: dictionary clojure

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

(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中找到地图中的匹配键和值是否有惯用方法?

2 个答案:

答案 0 :(得分:6)

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

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

=> true

我想说这是一种惯用的方式,对于大多数用例来说都可以正常工作。


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

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

=> true

你的功能行为相同:

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

=> true

要解决此问题,您可以使用get和#34;未找到"值:

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

答案 1 :(得分:2)

你的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))