我在Julia中有一些特殊定义的数组,你可以认为它只是许多数组的组合。例如:
type CompositeArray{T}
x::Vector{T}
y::Vector{T}
end
使用索引方案
getindex(c::CompositeArray,i::Int) = i <= length(c) ? c.x[i] : c.y[i-length(c.x)]
我有一点需要注意:较高的索引方案只是x
本身:
getindex(c::CompositeArray,i::Int...) = c.x[i...]
现在,通过它们的迭代器可以很容易地作为迭代器的链在x
上,然后在y
上。这使得迭代值几乎不需要额外的成本。但是,迭代到setindex!
可以做类似的事情吗?
我正考虑在CartesianIndex{2}
上单独发送,仅用于索引x
vs y
和索引,并为此构建eachindex
迭代器,类似于CatViews.jl does。但是,我不确定它将如何与i...
调度交互,或者在这种情况下是否有用。
此外,如果它是基于eachindex
构建的,广播会自动使用这种快速迭代方案吗?
编辑:
length(c::CompositeArray) = length(c.x) + length(c.y)
在实际情况中,x
可以是任何AbstractArray
(因此具有线性索引),但由于仅使用线性索引(除了那个面向用户{{1}这个问题真的归结为找出如何使用getindex
向量来做到这一点。
答案 0 :(得分:7)
使X[CartesianIndex(2,1)]
意味着与X[2,1]
不同的东西肯定不会结束。我希望X[100,1]
可能意味着与X[100]
或length(X) != prod(size(X))
不同的事实会带来类似的麻烦。您可以自由地违反规则,但是当Base和其他软件包中的函数希望您遵循它们时,您不应该感到惊讶。
执行此操作的安全方法是使eachindex(::CompositeArray)
在您完全控制的对象上返回自定义迭代器。如果该数据结构有用,可能只是向CartesianRange
和CartesianIndex{2}
抛出一个包装器并转发方法。然后,当您获得其中一个自定义索引类型时,您知道SplitIndex(CartesianIndex(1,2))
确实打算引用第二个数组中的第一个元素。