Map that describes a 2d vector -> 2d vector

Hi all.

Looking for assistance on how to create a function that takes a map of this format, for example:

{[1 0] 1
 [0 0] 2
 [1 1] 3
 [0 1] 4}

And returns a 2d vector that looks like, for example:

[[2 1]
 [4 3]]

So, the 2d vector represents an x,y grid where (0,0) is the upper left corner. The keys for the map are [x y] and the values for the map are the 2d vector values.

I’ve been attempting a solution trying different mixtures of for, reduce, map, assoc-in, update-in, etc. It’s been several days and I am not making progress so I appreciate any assistance. Thanks.

(let [in {[1 0] 1
          [0 0] 2
          [1 1] 3
          [0 1] 4}
      out [[2 1]
           [4 3]]
      ensure-index (fn [coll index val]
                     (let [count (count coll)
                           needed-count (inc index)]
                       (if (< count needed-count)
                         (into coll (repeat (- needed-count count) val))
                         coll)))]
  (= out 
     (reduce-kv
       (fn [acc [y x] v]
         (-> acc
             (ensure-index x [])
             (->> (mapv #(ensure-index % y nil)))
             (assoc-in [x y] v)))
       []
       in)))
;; => true

Also notice that x and y are swapped in reducing function, I made it to match your expected output, although I have a feeling it can be wrong. [0 1] coordinate should be 4 according to our input map, but (get-in out [0 1]) returns 1 — looks like axises are wrong in out

2 Likes

Thanks for the solution. I haven’t played around much with reduce-kv. Maybe that is the magic sauce needed to solve the problem :slight_smile:.

reduce-kv is almost the same as reduce, just a bit more efficient on maps because it avoids constructing map entries by passing key and value as separate arguments to reducing function

Morning @lkcampbell,

bellow is my very boring answer to your question. The main idea is to build from the empty answer [[nil nil] [nil nil]] the solution. For that, I use map-indexed to fetch the proper items in the input.

I did not put my answer in a standalone function for readability.

cheers!

didier

(def input {[1 0] 1
         [0 0] 2
         [1 1] 3
         [0 1] 4})

(defn replace-col [row-index col-index _]
   (get input [col-index row-index]))

(defn replace-row [row-index row]
   (map-indexed #(replace-col row-index %1 %2) row))

(def  empty-output (repeat 2 (repeat 2 nil)))
(map-indexed replace-row empty-output)
1 Like

Thanks for the input. I used your empty grid idea in my original attempts as well but couldn’t quite figure out how to consolidate the changes I made.

I have no experience using map-indexed yet but it looks like a very useful function for this problem. I will play around with it as well. Thanks.