Custom Iterators and Last Value

I’m trying to write an iterator for a custom data structure with the following as a test code:

struct DataStruct{TF<:AbstractFloat, TI<:Integer}
   X::Vector{TF}
   Y::Vector{TI}
end

function Base.length(D::DataStruct)
   return length(D.X)
end

function Base.eltype(D::DataStruct)
   return typeof((D.X[1], D.Y[1]))
end

function Base.iterate(D::DataStruct, state = ((D.X[1], D.Y[1]), 1))
   element, count = state
   if count >= length(D)
      return nothing
   end
   return (element, ((D.X[count+1], D.Y[count+1]), count+1))
end

n = 11;
D = DataStruct{Float64, Int}(range(0,stop=1, length=n), 2*ones(n));
for Z in D
   println(Z)
end

This code, obviously, misses the last element in the structure D, and I’m trying to understand the ‘‘proper’’ way to handle this.

Alternatively, would I just be better off doing?

for Z in zip(D.X,D.Y)
    println(Z)
end
if count > length(D)
    return nothing

You use a very nonstandard pattern in your iterator. Why keeping the element in the state? Start the state at 1 and increment it every call to iterate, stop when state is greater than the length of the arrays

function Base.iterate(D::DataStruct, state = 1)
   
   if state > length(D)
      return nothing
   end
   return  (D.X[state], D.Y[state]), state+1
end``
2 Likes