【问题标题】:Is there an idiomatic way to find matching key and value in map in Clojure?有没有一种惯用的方法可以在 Clojure 的地图中找到匹配的键和值?
【发布时间】:2015-02-07 04:57:15
【问题描述】:

我正在尝试从地图中查找匹配的键值对。我正在使用以下代码:

(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 的 map 中找到匹配的键和值?

【问题讨论】:

  • 您的 matches? 函数对我来说看起来不错,但在这种情况下我可能会删除 let:(defn matches? [m k v] (= (k m) v))
  • 请将其展开为答案

标签: dictionary clojure


【解决方案1】:

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

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

【讨论】:

  • 您可以在:not-found 示例中使用命名空间关键字::not-found 基本上消除了碰撞的可能性(除非有人故意尝试)。
  • 谢谢。我添加了一个冒号:)
【解决方案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))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-23
    • 1970-01-01
    • 1970-01-01
    • 2014-12-19
    • 2014-02-01
    • 1970-01-01
    相关资源
    最近更新 更多