Search code examples
clojure

Removing keys and values from map


I have a map that looks like this:

{\a [\h] 
 \h [\w \w]
 \i [\w \h \t]
 \p [\t \u \h \a]
 \s [\t \a \t \t \i \w \h]
 \t [\a]
 \u [\t \t \s]
 \w []}

I want to remove e.g. \w from both keys and values. i.e. leaving this

{\a [\h] 
 \h []
 \i [\h \t]
 \p [\t \u \h \a]
 \s [\t \a \t \t \i \h]
 \t [\a]
 \u [\t \t \s]}

Notice, the \w key has gone and \w has gone from all the values!

Right now I have this, which works, but I'm sure there must be a better, more Clojurey way!

(defn remove-last [last cmap]
  (reduce-kv (fn [acc k v]
               (if (empty? v)
                 acc
                 (into acc {k (vec (filter #(not= % last) v))}))) {} cmap))

The key to remove will always be an empty vector.

How can I do this better?


Solution

  • I find your solution quite idiomatic. The requirement is unusual enough, that I immediately think reduce. Your call to empty? is not according to your spec, though. You'd have to test for the key k being = to last.

    Also, I wouldn't use the name last here. It clashes with a name that is already present.

    A very similar alternative would be

    (defn remove-all-of [it m] 
      (reduce
       (fn [acc [k v]] 
         (if (not= it k)
           (assoc acc
                  k
                  (into (empty v)
                        (filter #(not= it %) v)))
           acc))
       {}
       m))
    

    This also allows you to have some other seqable thing than vectors as values by using (empty v).