快速索引数组

时间:2015-12-02 08:20:56

标签: arrays indexing julia

访问(并且可能替换)大型多维数组中的条目的最有效方法是什么?我在循环中使用这样的东西:

tup = (16,45,6,40,3)
A[tup...] = 100

但我想知道是否有更有效的方法。特别是,有没有办法可以避免使用...

3 个答案:

答案 0 :(得分:5)

要迭代多维数组,建议执行for index in eachindex(A);见例如。

https://groups.google.com/forum/#!msg/julia-users/CF_Iphgt2Wo/V-b31-6oxSkJ

如果A是标准数组,那么这对应于使用单个整数进行索引,这是访问数组的最快方式(原始问题):

A = rand(3, 3)

for i in eachindex(A)
   println(i)
end

但是,如果A是一个更复杂的对象,例如一个子阵列,然后eachindex(A)会给你一个不同的,有效的访问对象:

julia> for i in eachindex(slice(A, 1:3, 2:3))
           println(i)
       end

给出

CartesianIndex{2}((1,1))
CartesianIndex{2}((2,1))

答案 1 :(得分:5)

并不总是涉及泼溅的惩罚,但确定它的效率并不总是显而易见(或容易)。您的简单示例实际上与编写A[16,45,6,40,3] = 100一样有效。您可以通过比较来看到这一点

   function f(A)
       tup = (16,45,6,40,3)
       A[tup...] = 100
       A
   end
   function g(A)
       A[16,45,6,40,3] = 100
       A
   end
julia> code_llvm(f, Tuple{Array{Int, 5}})
# Lots of output (bounds checks).
julia> code_llvm(g, Tuple{Array{Int, 5}})
# Identical to above

如果有罚款,你会以分配的形式看到它。您可以使用@allocated宏进行测试,或者只需检查code_llvm以获取对@jl_pgcstack的引用 - 这是垃圾收集器,这是任何时候都需要的。分配。请注意,在更复杂的函数中很可能还会导致分配,因此它的存在并不一定意味着存在splatting悲观。但是如果这是一个热循环,你想要最小化所有分配,所以它是一个很好的目标......即使你的问题不是由于splatting。您还应该使用@code_warntype,因为类型不佳的代码肯定会使splats和许多其他操作失望。如果您的元组输入不好,将会发生什么:

   function h(A)
       tup = ntuple(x->x+1, 5) # type inference doesn't know the type or size of this tuple
       A[tup...] = 100
       A
   end
julia> code_warntype(h, Tuple{Array{Int,5}})
# Lots of red flags

因此,优化此splat将高度依赖于您构建或获取tup的方式。

答案 2 :(得分:-1)

索引多维数组的最快方法是线性索引 Base.Base.linearindexingBase模块中的一个相关函数,用于查找最有效的访问方式到数组元素。

julia> a=rand(1:10...);
julia> Base.Base.linearindexing(a)
Base.LinearFast()

可以使用ii=sub2ind(size(A),tup...)语法将索引元组转换为一个线性索引或for i in eachindex(A)来遍历它。