Recently, I've been starting out with clojure programming and functional programming in general. One thing I noticed, solving some basic programming puzzles, is that there is no index-of function for vectors, eg. no reverse for the core function nth
. I've seen people implement it themselves or use some java substitute implementation.
My question isn't as much if there's a workaround (but if you know of a particularly elegant one, share it), because I know there is. What I'm wondering is: why is this the case, eg. why did the clojure developers decide against implementing what seems like such a basic operation. Is doing a position lookup in a vector somehow non-idiomatic in clojure and would ideally be done in other ways? How?
There is a standard Clojure function that almost does what the problem requires.
If we look at the skeleton source, what we need to do is invert a sequence such as ...
(def ranks [2 3 4 5 6 7 8 9 10 :jack :queen :king :ace])
... into a map (or other function) that gives us the index of every value:
{7 5, :king 11, 4 2, :queen 10, :ace 12, 6 4, 3 1, 2 0, :jack 9, 9 7, 5 3, 10 8, 8 6}
We can do this once and for all.
The standard function that nearly does this is clojure.set/map-invert
.
So a simple function to invert a vector (or other sequence) into an index function is ...
(defn indexes-of [v]
(->> v
(map-indexed vector)
(clojure.set/map-invert)))
For example,
(indexes-of ranks)
=> {7 5, :king 11, 4 2, :queen 10, :ace 12, 6 4, 3 1, 2 0, :jack 9, 9 7, 5 3, 10 8, 8 6}
So the folks who say that you've got the wrong end of the stick are correct. However, it is surely better to perform a domain-free computation like this within Clojure itself, however smoothly Clojure docks with whatever VM it happens to be running on.
What we need is a cloak to throw over a vector to make it into a map: just as rseq
throws a cloak over a vector, making it appear as a reversed sequence. Then we need not assume that map-invert
will accept a sequence of pairs. (To be safe now, we could feed the sequence of pairs into
a map to feed to map-invert
).