有没有一种惯用的方法可以在 Clojure 的地图中找到匹配的键和值?
Is there an idiomatic way to find matching key and value in map in 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 的映射中是否有惯用的方法来查找匹配的键和值?
你的 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))
这可能是一个足够小的问题,您可以使用它而不是定义函数:
(= ({:a 1 :b 2} :a)
1)
=> true
我会说这是一种惯用的方式,适用于大多数用例。
但是,这取决于您在测试 nil
值时所需的行为。因为上述方法将 return true
for :c nil
:
(= ({:a 1 :b 2} :c)
nil)
=> true
您的函数的行为方式相同:
(matches? {:a 1 :b 2} :c nil)
=> true
要解决这个问题,您可以使用 get
和 "not found" 值:
(= (get {:a 1 :b 2} :c ::not-found)
nil)
=> false
这工作正常,但可能不那么整洁。您只需要确保您的 "not found" 值永远不会与您的测试值相同。
如果您想真正知道地图包含一个可能具有 nil
值的键,您将不得不同时检查这两项。这是一个只执行一次哈希映射查找的函数。它使用 (find map key)
,其中 return 是键的映射条目(键值对),如果键不存在则为 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
我正在尝试从地图中查找匹配的键值对。我正在使用以下代码:
(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 的映射中是否有惯用的方法来查找匹配的键和值?
你的 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))
这可能是一个足够小的问题,您可以使用它而不是定义函数:
(= ({:a 1 :b 2} :a)
1)
=> true
我会说这是一种惯用的方式,适用于大多数用例。
但是,这取决于您在测试 nil
值时所需的行为。因为上述方法将 return true
for :c nil
:
(= ({:a 1 :b 2} :c)
nil)
=> true
您的函数的行为方式相同:
(matches? {:a 1 :b 2} :c nil)
=> true
要解决这个问题,您可以使用 get
和 "not found" 值:
(= (get {:a 1 :b 2} :c ::not-found)
nil)
=> false
这工作正常,但可能不那么整洁。您只需要确保您的 "not found" 值永远不会与您的测试值相同。
如果您想真正知道地图包含一个可能具有 nil
值的键,您将不得不同时检查这两项。这是一个只执行一次哈希映射查找的函数。它使用 (find map key)
,其中 return 是键的映射条目(键值对),如果键不存在则为 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