2013-05-03 12 views
13

Gibt es in der Clojure-Bibliothek eine Funktion "assoc-if"? Wenn ein Wert truthig ist, aktualisieren Sie eine Karte mit einem bestimmten Schlüsselwert. Ich habe versucht, etwas in diesem Sinne zu finden, aber es kam zu wenig.Assoc-if in Clojure

(defn assoc-if 
    [m key value] 
    (if value (assoc m key value) m)) 
+0

Nichts als solches – Ankur

Antwort

18

Wenn das Ziel zu vermeiden, ist m wiederholen, können Sie conj verwenden:

(conj m (when value [key value])) 

... oder Clojure 1.5 Der neue Threading-Makros:

(-> m 
    (cond-> value (assoc key value))) 

Wenn es tatsächlich wichtig, sowohl die m und value zu wiederholen, werden Sie Ihre eigenen oder erreichen außerhalbschreiben müssen

+1

'cond->' ist eine nette Antwort hier, denke ich. – charleslparker

7

Es gibt keine build-in assoc-if Funktion in Clojure, aber du bist nicht der erste, der es braucht. Check this link mit einer Implementierung von assoc-if von ALEX MILLER:

(defn ?assoc 
    "Same as assoc, but skip the assoc if v is nil" 
    [m & kvs] 
    (->> kvs 
    (partition 2) 
    (filter second) 
    flatten 
    (apply assoc m))) 

Aber da flatten ist rekursiv, es am besten ist es mit etwas zu ersetzen, die nicht (dank kotarak für den Hinweis) ist. Ein weiteres Problem dieser Implementierung ist, dass (apply assoc m) in einer leeren Liste fehlschlägt. So ist es am besten, es zu ersetzen:

(defn ?assoc 
    "Same as assoc, but skip the assoc if v is nil" 
    [m & kvs] 
    (->> kvs 
    (partition 2) 
    (filter second) 
    (map vec) 
    (into m))) 
+1

Ich würde die 'flatten' und' assoc' durch 'vec' und' in' ersetzen. '(- >> kvs (Partition 2) (Filter Sekunde) (map vec) (in m))'. 'flatten' ist rekursiv, was höchstwahrscheinlich nicht das ist, was Sie wollen. – kotarak

+0

Sie haben Recht mit 'flatten', aber ich denke, es ist am besten, es einfach durch' (concat) zu ersetzen ''. –

+0

Aber, auf den zweiten Gedanken, '(apply assoc m)' wird auf leere Liste fehlschlagen und '(in m)' wird nicht. –