2015-02-07 42 views
2

我正試圖從地圖中找到匹配的鍵和值對。我使用下面的代碼:在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的地圖中是否有一種慣用的方式來查找匹配的鍵和值?

+1

你''匹配功能對我來說很好,但我可能會刪除讓這種情況下:'(DEFN匹配?[mkv](=(km)v))'。 – 2015-02-07 08:28:03

+0

請將其擴展爲答案 – hawkeye 2015-02-07 08:31:50

回答

6

這可能是一個足夠小的問題,你可以只使用這個,而不是定義一個函數:

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

您可以在你的':not-found'例子中使用命名空間關鍵字':: not-found'來基本消除碰撞的可能性(除非有人故意嘗試)。 – xsc 2015-02-07 11:27:09

+0

謝謝。我已經添加了一個冒號:) – TheQuickBrownFox 2015-02-08 09:24:57

2

matches?您的matches?函數看起來不錯,但我可能會刪除在這種情況下,因爲它消除了一些混亂。我也想它重命名爲更精確的,雖然這是我能拿出剛纔最好的:

(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)) 
相關問題