Enumerate Vector Sequences

The enumerate_seq iterator is also used in the algorithm to trace hiatus in sediment accumulation. Here the task is to enumerate a nested sequence while preserving the nested structure.

⪡algorithms-spec⪢≣
a = [[:a, :b], [:c]]
@test collect(enumerate_seq(a)) == [[(1, :a), (2, :b)], [(3, :c)]]
file:src/Algorithms/EnumerateSeq.jl
module EnumerateSeq

struct TagVectors{T}
    vectors::T
end

function Base.iterate(tv::TagVectors{T}) where T
    tag = 1
    x = iterate(tv.vectors)
    isnothing(x) && return nothing
    (v_, nit) = x
    v = collect(v_)
    n = length(v)
    return zip(tag:tag+n-1, v) |> collect, (tag+n, nit)
end

function Base.iterate(tv::TagVectors{T}, st::Tuple{Int,U}) where {T, U}
    (tag, it) = st
    isnothing(it) && return nothing
    x = iterate(tv.vectors, it)
    isnothing(x) && return nothing
    (v_, nit) = x
    v = collect(v_)
    n = length(v)
    return zip(tag:tag+n-1, v) |> collect, (tag+n, nit)
end

Base.IteratorSize(::Type{TagVectors{T}}) where T = Base.IteratorSize(T)
Base.size(r::TagVectors{T}) where T = size(r.vectors)
Base.length(r::TagVectors{T}) where T = length(r.vectors)
Base.eltype(::Type{TagVectors{T}}) where T = Any
# This should be:
# Iterators.Zip{Tuple{UnitRange{Int},Vector{eltype(eltype(T))}}}
# But that doesn't work

"""
    enumerate_seq(s)

Enumerates an iterator of sequences, such that the following equivalence
holds,

    enumerate(flatten(s)) == flatten(enumerate_seq(s))

while keeping the underlying structure intact.
"""
enumerate_seq(s::T) where T = TagVectors{T}(s)

export enumerate_seq

end