I would worry less about getting rid of loops (which are perfectly fine in Julia) and more about making your complexity better. Right now, your computational cost scales proportionally to length(v) * sum(length, u), which is pretty bad if the vectors are long. You can do much better.
For example, make a single pass over u first to make a dictionary mapping values to indices:
d = Dict{eltype(eltype(u)),Int}()
for i in eachindex(u), x in u[i]
d[x] = i
end
which has nearly linear complexity in the two lengths. You might also want to consider using the dictionary (or similar) in the first place to store your mapping (so that you never create u at all).
(And you can do even better if you have more knowledge of u. e.g. if you know that the elements of u cover all of the values of v, and that these are small integers β as in your example above β then you can just store an array mapping values to indices, rather than a dictionary.)
This option uses the fact u is a partition of the values of v, and the size 5 of the value set of v is encoded in the initialization. But it feels this knowledge is implicit in the OP setup.
This is cute, but still has poor time complexity proportional to length(v) * sum(length, u), as well as poor space complexity due to allocating a temporary matrix of size length(v) * length(u).
It still has poor time complexity proportional to length(v) * sum(length, u).
Also has the same poor time complexity.
Realize that nearly all of the solutions posted so far (excluding mine) correspond to three nested loops, hence the multiplicative complexity. Squeezing the code into a minimal number of library calls is fine if you want to minimize code size, but itβs too easy to fall into the myth of βlibrary calls = fastβ, or to think only about code size and not about computational complexity.
In general terms I would say yes.
In my experience (I often try to independently create scripts that replace/improve library calls) and with my level of knowledge, library calls work better.
But I wonder if in the specific case, being u something like a partition of unique[v], the evaluation of the spatial or temporal complexity is not different from the general worst case.
Hopefully, the βnearlyβ refers to my solution too. Which has the same low complexity. In fact, due to implementation of Dicts, assuming, as it seems, that u is a partition of 1:n (n=5 here), my solution would keep a multlipicative advantage in larger scales (both in memory and speed). stevengj already mentions this possibility at the end of his solution, so perhaps Iβve added nothing novel.
βLibrary calls are fasterβ is an unreliable heuristic.
First, you should always try to have some sense of what the library calls are doing β at least know the expected complexity. (e.g. findfirst(predicate, array) or x in array are both sequential search, so have an average cost that scales with the array length multiplied by the cost of the predicate).
Second, as I wrote in another blog post: There is a tension between two general principles in computing: on the one hand, re-using highly optimized code is good for performance; on the other other hand, optimized code that is specialized for your problem can usually beat general-purpose functions.
That being said, there is absolutely nothing wrong with writing code to minimize code length or maximize clarity (hopefully both) rather than optimizing speed. But you should be aware that you are doing so, especially if your code has suboptimal complexity/scaling (not just a suboptimal constant factor, which requires a lot more expertise to deal with).
Right, your solution also does one linear-time pass over u and one linear-time pass over v.