1
votes

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?

3

3 Answers

2
votes

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).

8
votes

what i would propose, is to first dissoc the \w key from the map (considering this is ~constant time operation), and then use the transducer to reshape the sequence in one pass without losing the declarative style, and to eliminate verbosity of reduce, while keeping the performance. could look like this:

(into {}
      (map (fn [[k v]] [k (filterv #(not= \w %) v)]))
      (dissoc data \w))

as for me, i consider this to be more readable, than reduce/assoc or reduce/update

4
votes

I like specter so much:

(s/setval (s/walker (fn-> (= \w))) s/NONE {\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 []})