Getting it right
We can define the required function as
(defn update-submatrix [m sub-m [x y]]
(replace-subvec
m
(map (fn [l r] (replace-subvec l r y)) (subvec m x) sub-m)
x))
... where (replace-subvec v s start)
replaces the elements of vector v
from index start
with those of sequence s
, as long as s
lasts. For example,
(replace-subvec (vec (range 10)) (range 3) 5)
; [0 1 2 3 4 0 1 2 8 9]
A clear but slow implementation is
(defn replace-subvec [v s start]
(vec (concat (subvec v 0 start) s (subvec v (+ start (count s))))))
... giving, for the example in the question,
(def submatrix [[1 1] [1 1]])
(def matrix [[0 0 0] [0 0 0] [0 0 0]])
(def pos [1 1])
(update-submatrix matrix submatrix pos)
; [[0 0 0] [0 1 1] [0 1 1]]
Speeding it up
The key to speeding up update-submatrix
is to speed up replace-subvec
.
We can do so in two ways:
- run through the altered elements by incrementing through a loop, and
- use a transient collection within the function.
This gives us
(defn replace-subvec [v s start]
(loop [v (transient v), s s, i start]
(if (empty? s)
(persistent! v)
(recur (assoc! v i (first s)) (rest s) (inc i)))))
The effect is identical.