如何迭代除AbstractArray的最后一个索引之外的所有索引

tim*_*tim 5 iteration julia

在Julia中,迭代所有索引的推荐方法AbstractArray是使用eachindex,例如,

for i in eachindex(a)
    do_something(a[i], i)
end
Run Code Online (Sandbox Code Playgroud)

与此相反1:length(a),eachindex(a)支持具有非常规索引的数组,即不从中开始的索引1.此外,对于具有慢线性索引的阵列,它更有效.

如果我想跳过我可以使用的第一个索引Iterators.drop(eachindex(a), 1)(有更好的方法吗?)但是如何以通用方式跳过最后一个?

Mat*_* B. 5

"前"迭代器相对简单并且通常是有用的.编辑:仅仅针对这种情况完全一般地定义它也是完全过分的.依赖Base的内置函数更简单,更简单,定义如下:

front(itr, n=1) = Iterators.take(itr, length(itr)-n)
Run Code Online (Sandbox Code Playgroud)

这适用于所有已length定义的迭代器- 它将包含eachindex将返回的所有内容.


或者,您可以根据不依赖于length定义的第一原则定义专用迭代器.我不知道任何现有包中的这种结构.使用Julia 0.6,实现可能如下所示:

struct Front{T}
    itr::T
end
# Basic iterator definition
function Base.start(f::Front)
    s = start(f.itr)
    done(f.itr, s) && throw(ArgumentError("cannot take the front of an empty iterator"))
    return next(f.itr, s)
end
function Base.next(f::Front, state)
    val, s = state
    return val, next(f.itr, s)
end
Base.done(f::Front, state) = done(f.itr, state[2])

# Inherit traits as appropriate
Base.iteratorsize(::Type{Front{T}}) where {T} = _dropshape(Base.iteratorsize(T))
_dropshape(x) = x
_dropshape(::Base.HasShape) = Base.HasLength()
Base.iteratoreltype(::Type{Front{T}}) where {T} = Base.iteratoreltype(T)
Base.length(f::Front) = length(f.itr) - 1
Base.eltype(f::Front{T}) where {T} = eltype(T)
Run Code Online (Sandbox Code Playgroud)

现在:

julia> collect(Front(eachindex(rand(5))))
4-element Array{Int64,1}:
 1
 2
 3
 4

julia> collect(Front(eachindex(sprand(3, 2, .2))))
5-element Array{CartesianIndex{2},1}:
 CartesianIndex{2}((1, 1))
 CartesianIndex{2}((2, 1))
 CartesianIndex{2}((3, 1))
 CartesianIndex{2}((1, 2))
 CartesianIndex{2}((2, 2))
Run Code Online (Sandbox Code Playgroud)

  • 然而,对于`take(OneTo(n),m)`返回`OneTo(min(n,m))`和`UnitRange`的类似方法仍然有意义.这将消除两个最常见的`eachindex`案例的开销.我可能会在以后提出PR. (2认同)