【问题标题】:Julia redefining indices when accessing an arrayJulia在访问数组时重新定义索引
【发布时间】:2019-03-27 14:46:54
【问题描述】:

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

可以使用: (Colon)、UnitRangeStepRangeOneToIntInt arrays 访问数组元素,所以我应该在哪里重新定义索引而不必管理所有这些案例?

【问题讨论】:

  • “重新定义”是什么意思?你能举一个你想要发生的事情的例子吗?
  • 例如,置换索引并对它们应用转换 (i = f(i))

标签: indexing julia


【解决方案1】:

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

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] 是使用转换前的索引还是转换后的索引。

【讨论】:

  • 你是对的,在这个例子中谈论它更容易。在这个例子中(这离我想要做的不远),如果你调用 R[:,:] 会出现性能问题,因为 eachindex 将以非最佳顺序迭代笛卡尔索引。有没有办法告诉 Julia 这个数组的最佳迭代顺序是什么?
猜你喜欢
  • 2021-09-17
  • 1970-01-01
  • 2020-07-16
  • 1970-01-01
  • 2012-12-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-17
相关资源
最近更新 更多