If I have a vector defined as
(def matrix [[1 2 3][4 5 6]])
How in clojure do I access a random element in a vector of vectors? I keep seeing people say online that one of the benefits to using a vector over a list is that you get random access instead of having to recurse through a list but I haven't been able to find the function that allows me to do this. I'm used to in c++ where I could do matrix[1][1] and it would return the second element of the second vector.
Am I stuck having to loop one element at a time through my vector or is there an easier way to access specific elements?
Almost like you would do it in C++:
user=> (def matrix [[1 2 3][4 5 6]])
user=> (matrix 1)
[4 5 6]
user=> ((matrix 1) 1)
5
As the docs say:
Vectors implement IFn, for invoke() of one argument, which they presume is an index and look up in themselves as if by nth, i.e. vectors are functions of their indices.
Vectors are associative, so you can use get-in
to access nested vectors, e.g. matrices, by coordinates.
(def matrix [[1 2 3] [4 5 6] [7 8 9]])
(get-in matrix [1 1])
;=> 5
Since vectors are associative data structures, you can also use get-in to reach inside with nested indices:
user=> (def matrix [[1 2 3][4 5 6]])
user=> (get-in matrix [1 1])
5
The other answers are probably all that you need, but if you're doing 2D indexing a lot--perhaps along with other transformations of 2D numeric structures--you might want to look into the core.matrix library. Switching between different core.matrix implementations with different performance characteristics is usually a one-line change. One of the implementations consists of operations on Clojure vectors. Here's how you would do the double-indexing in core.matrix:
user=> (use 'clojure.core.matrix)
nil
user=> (def m (matrix [[1 2 3][4 5 6]]))
#'user/m
user=> (mget m 1 1)
5
For that particular operation, core.matrix provides no particular advantage. If you want to iterate through the matrix to generate a new one, here's one way to do it:
user=> (emap inc m)
[[2 3 4] [5 6 7]]
Of course it's not very hard to do that with core Clojure functions. Whether core.matrix is useful depends on what you want to do, obviously.
You can use the same approach to Mars answer above, with to-array-2d
implemented in clojure.core
library :)
user> (def a (to-array-2d [[1 2 3][4 5 6]]))
#'user/a
user> (alength a)
2
user> (alength (aget a 0))
3
user> (aget a 0 0)
1
user> (aget a 0 1)
2
user> (aget a 0 2)
3
user> (aget a 1 0)
4
user> (aget a 2 0)
ArrayIndexOutOfBoundsException