Julia在访问数组时重新定义索引

时间:2019-03-27 14:46:55

标签: indexing julia

我有一个实现Array接口的结构。我想在访问它时重新定义索引。到目前为止,我已经在我的类型的Base.getindex函数中做到了,但是我已经在文档中看到了Base.to_indices函数,并且不知道它们如何协同工作。

可以使用:Colon),UnitRangeStepRangeOneToInt或{{ 1}},那么我应该在哪里重新定义索引而不必处理所有这些情况?

1 个答案:

答案 0 :(得分:2)

很难抽象地讨论这一点。这是一个具体的例子:

struct ReversedRowMajor{T,A} <: AbstractMatrix{T}
    data::A
end
ReversedRowMajor(data::AbstractMatrix{T}) where {T} = ReversedRowMajor{T, typeof(data)}(data)
Base.size(R::ReversedRowMajor) = reverse(size(R.data))
Base.getindex(R::ReversedRowMajor, i::Int, j::Int) = R.data[end-j+1, end-i+1]

这个简单的数组访问父数组,并对其索引进行置换(将其变为行主)并进行转换(将其反转)。请注意,此数组会自动支持所有预期的索引形式:

julia> R = ReversedRowMajor([1 2; 3 4; 5 6])
2×3 ReversedRowMajor{Int64,Array{Int64,2}}:
 6  4  2
 5  3  1

julia> R[:, isodd.(R[1,:].÷2)]
2×2 Array{Int64,2}:
 6  2
 5  1

julia> @view R[[1,4,5]]
3-element view(reshape(::ReversedRowMajor{Int64,Array{Int64,2}}, 6), [1, 4, 5]) with eltype Int64:
 6
 3
 2

请注意,我们不会使用排列后的索引和计算后的索引重新索引到R中—新索引直接提供给父数组R.data

现在,to_indices另一方面将以前不受支持的索引 types 转换为IntInt的数组,然后重新使用这些转换后的索引将索引自身R中索引。请注意当您致电R[Int8(1),Int8(1)]时会发生什么:

julia> @which R[Int8(1),Int8(1)]
getindex(A::AbstractArray, I...) in Base at abstractarray.jl:925

这没有调用您定义的任何方法-尚未。您尚未定义如何getindex(::ReversedRowMajor, ::Int8, ::Int8)。因此,朱莉娅正在为您处理此案。它使用to_indicesInt8转换为Int,然后再次调用R[1,1] 。现在,它会命中您定义的方法。

简而言之:该数组具有一个简单的getindex方法,该方法带有Int索引,可将访问重新计算为父数组。另一方面,在您尚未定义匹配方法的情况下,to_indices会将所有其他类型的索引转换为支持的索引到同一数组。您根本无法使用to_indices进行所需的转换,因为不清楚R[1, 2]是使用转换前的索引还是转换后的索引。