1

Consider this map:

(def my-map {:a-vec []}) 

Now I want to append some value to a-vec:

(assoc my-map :a-vec (conj (:a-vec my-map) 17)) 

What I don't like about this is that I name both the map and the key twice.

In actual code I have this function:

(defn update-game-objects [objs col-key brick] (-> objs (assoc col-key (conj (col-key objs) brick)) ; <- check here (update-in [:temp :x] inc))) 

Notice how I explicitly access objs, the same one that is threaded through. This should be a big no-no and only works in this case, because it is on the first line of the threading macro. Otherwise I might undo changes to objs done before.

Regarding my first example again, ideally I would like to have a function like this:

(assoc-conj my-map :a-vec 17) 

I haven't found a function like this, but is there another way to append to a vector inside a map, referencing the map and the key only once?

0

1 Answer 1

0

Macros to the rescue:

(defmacro assoc-conj "conjoin to a collection inside a map" [m k v] (list assoc m k (list conj (list get m k) v))) 

With that, above call just works:

(assoc-conj my-map :a-vec 17) ;;=> {:a-vec [17]} 

Edit: Please check @Eugene's comment for an even better solution.

Sign up to request clarification or add additional context in comments.

2 Comments

Why would you use a macro? You already have update-in in your code, so just use that. Given how col-key is a single key and not a collection of keys, you can use update instead: (update my-map :a-vec conj 17). Macros are very close to the end of the list of things you want to reach out to when searching for a solution.
Awesome. I think I hadn't fully understand how update works. I agree that this solution is easier.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.