(ns quoin.map-access "Routines to examine and modify maps, counting keys that have the same name as identical (ie, :blah and \"blah\" identify the same key).") (defn contains-named? "Given a map and a key, returns \"true\" if the map contains the key, allowing for differences of type between string and keyword. That is, :blah and \"blah\" are the same key. The key of the same type is preferred. Returns the variant of the found key for true, nil for false." ([map key] (contains-named? map key nil)) ([map key not-found] (if (contains? map key) key (if (keyword? key) (let [str-key (name key)] (if (contains? map str-key) str-key not-found)) (let [kw-key (keyword key)] (if (contains? map kw-key) kw-key not-found)))))) (defn get-named "Given a map and a key, gets the value out of the map, trying various permitted combinations of the key. Key can be either a keyword or string, and is tried first as it is, before being converted to the other." ([map key] (get-named map key nil)) ([map key not-found] (get map (contains-named? map key) not-found))) (defn assoc-named "Just like clojure.core/assoc, except considers keys that are keywords and strings equivalent. That is, if you assoc-named :keyword into a map with a key \"keyword\", the latter is replaced." ([map key val] (let [found-key (contains-named? map key key)] (assoc map found-key val))) ([map key val & kvs] (let [new-map (assoc-named map key val)] (if kvs (recur new-map (first kvs) (second kvs) (nnext kvs)) new-map)))) (defn dissoc-named "Given a map and key(s), returns a map without the mappings for the keys, allowing for the keys to be certain combinations (ie, string/keyword are equivalent)." ([map] map) ([map key] (if-let [found-key (contains-named? map key)] (dissoc map found-key))) ([map key & ks] (let [new-map (dissoc-named map key)] (if ks (recur new-map (first ks) (next ks)) new-map))))