Reputation: 58
I build a 2-dimensional array (a matrix) consisting of a vector of vectors:
(setq zero-row [0 0 0 0 0])
=> [0 0 0 0 0]
(setq zero-mat (make-vector 4 zero-row))
=> [[0 0 0 0 0] [0 0 0 0 0] [0 0 0 0 0] [0 0 0 0 0]]
I'll set the element in row 2, column 3 (0-indexed) to 42 by replacing row 2 with a vector containing the changed element:
(aset zero-mat 2 [0 0 0 42 0])
=> [0 0 0 42 0]
zero-mat
=> [[0 0 0 0 0] [0 0 0 0 0] [0 0 0 42 0] [0 0 0 0 0]]
It works.
Next I try to build a function which takes this approach to set the (i,j)-th element in such a 2-dimensional array:
(defun matrix-set (mat i j elt)
"Set the (i, j)-th element of mat to elt. mat is a vector of the row vectors. Indexing is 0-based in each component."
(let ((vect (aref mat i)))
(aset vect j elt)
(aset mat i vect)
mat))
But this doesn't work:
(setq zero-row [0 0 0 0 0])
=> [0 0 0 0 0]
(setq zero-mat (make-vector 4 zero-row))
=> [[0 0 0 0 0] [0 0 0 0 0] [0 0 0 0 0] [0 0 0 0 0]]
(matrix-set zero-mat 2 3 42)
=> [[0 0 0 42 0] [0 0 0 42 0] [0 0 0 42 0] [0 0 0 42 0]]
It looks like all the rows of the array are linked to the same vector, so changing that vector changes all the rows.
So two questions: (1) Why is this happening in the second case, but not the first? (2) How can I fix this (so I can access the (i, j)-th entry of a 2-dim. array represented this way)?
(I was originally writing a little routine to add two matrices, represented as vectors of vectors as above, and ran into the same problem. I think the stripped-down example above may make the problem clearer.)
Upvotes: 3
Views: 767
Reputation:
In the first case you are replacing an element in the "outer" vector by another vector (while other three "inner" vectors still point all to the same element). In the second case you replace an element in the "inner" vector (and you have only one inner vector duplicated four times, as per your example. A simple way to initialize vector to different distinct vectors would be something like this:
(let ((i 0) (new-vector (make-vector 4 nil))
(while (< (progn (aset new-vector i (make-vector 5 0))
(incf i))
(length new-vector)))
Sorry if there are any typos, was writing it in-place. But the idea should be simple enough to figure it out.
Upvotes: 3