There you go:
julia> function getci!(M,k,cmins,vmins) # inplace
ci = CartesianIndices(size(M))
for i in 1:k
cmins[i] = ci[i]
vmins[i] = M[i]
end
imin = findmin(vmins)[2]
for i in firstindex(M)+k:lastindex(M)
if M[i] > vmins[imin]
cmins[imin] = ci[i]
vmins[imin] = M[i]
imin = findmin(vmins)[2]
end
end
return cmins, vmins
end
function getci(M,k) # allocating
cmins = Vector{CartesianIndex{2}}(undef,k)
vmins = Vector{eltype(M)}(undef,k)
return getci!(M,k,cmins,vmins)
end
getci (generic function with 1 method)
julia> A = [3 1 1
1 3 3]
2×3 Matrix{Int64}:
3 1 1
1 3 3
julia> @btime getci($A,3)
78.857 ns (2 allocations: 240 bytes)
(CartesianIndex{2}[CartesianIndex(1, 1), CartesianIndex(2, 2), CartesianIndex(2, 3)], [3, 3, 3])
julia> cmins=Vector{CartesianIndex{2}}(undef,3); vmins=Vector{Int}(undef,3);
julia> @btime getci!($A,3,$cmins,$vmins)
35.864 ns (0 allocations: 0 bytes)
(CartesianIndex{2}[CartesianIndex(1, 1), CartesianIndex(2, 2), CartesianIndex(2, 3)], [3, 3, 3])
(since here there is an auxiliary array with the associated values, why not return it)
(for rand(20,20)
and k=2
, an example you mentioned this is 10 times faster than the alternative:
julia> A = rand(20,20); k = 2;
julia> @btime klargest_indexes($A,2)
5.540 μs (8 allocations: 3.56 KiB)
2-element Vector{CartesianIndex{2}}:
CartesianIndex(14, 8)
CartesianIndex(10, 10)
julia> @btime getci($A,2)
549.492 ns (2 allocations: 208 bytes)
(CartesianIndex{2}[CartesianIndex(10, 10), CartesianIndex(14, 8)], [0.9941985771967297, 0.9992607929792117])
julia> cmins=Vector{CartesianIndex{2}}(undef,k); vmins=Vector{eltype(A)}(undef,k);
julia> @btime getci!($A,2,$cmins,$vmins);
509.870 ns (0 allocations: 0 bytes)