Repository: JuliaLang/julia
File: base/iterators.jl (Julia)

Code before:
reverse(x::IterableStatePairs{<:Iterators.Reverse}) = IterableStatePairs(x.x.itr)

function iterate(x::IterableStatePairs{<:Iterators.Reverse}, state=last(keys(x.x.itr)))
    it = iterate(x.x, state)
    it === nothing && return nothing
    (state => first(it), last(it))
end

# According to the docs of iterate(::AbstractString), the iteration state must
# be the same as the keys, so this is a valid optimization (see #51631)
pairs(s::AbstractString) = IterableStatePairs(s)

"""
    nth(itr, n::Integer)

Get the `n`th element of an iterable collection. Return `nothing` if not existing.

See also: [`first`](@ref), [`last`](@ref)

# Examples
```jldoctest
julia> nth(2:2:10, 4)
8

julia> nth(reshape(1:30, (5,6)), 6)
6
```
"""
nth(itr, n::Integer) = _nth(IteratorSize(itr), itr, n)
nth(itr::AbstractArray, n::Integer) = n > length(itr) ? nothing : itr[n]

_nth(::SizeUnknown, itr, n) = _fallback_nth(itr, n)
_nth(::Union{HasShape,HasLength}, itr, n) = _withlength_nth(itr, n, length(itr))
_nth(::IsInfinite, itr, n) = _inbounds_nth(itr, n)

_inbounds_nth(itr, n) = iterate(drop(itr, n - 1))[1]
_inbounds_nth(itr::AbstractArray, n) = itr[n]

_withlength_nth(itr, n, N) = n > N ? nothing : _inbounds_nth(itr, n)

function _fallback_nth(itr, n)
    y = iterate(drop(itr, n - 1))
    y === nothing && return nothing
    y[1]
end

# specialized versions to better interact with existing iterators
# Count
nth(itr::Count, n::Integer) = n > 0 ? itr.start + itr.step * (n - 1) : nothing

# Repeated

Review comment (suggestion):
I would also mention that it will advance the iterator `n` steps, and perhaps show an example of how it affects a stateful iterator in the examples:
```
julia> stateful = Stateful(1:10); nth(stateful, 7)
7

julia> first(stateful)
8
```

Code after:

function iterate(x::IterableStatePairs, state=first(keys(x.x)))
    it = iterate(x.x, state)
    it === nothing && return nothing
    (state => first(it), last(it))
end

reverse(x::IterableStatePairs) = IterableStatePairs(Iterators.reverse(x.x))
reverse(x::IterableStatePairs{<:Iterators.Reverse}) = IterableStatePairs(x.x.itr)

function iterate(x::IterableStatePairs{<:Iterators.Reverse}, state=last(keys(x.x.itr)))
    it = iterate(x.x, state)
    it === nothing && return nothing
    (state => first(it), last(it))
end

# According to the docs of iterate(::AbstractString), the iteration state must
# be the same as the keys, so this is a valid optimization (see #51631)
pairs(s::AbstractString) = IterableStatePairs(s)

"""
    nth(itr, n::Integer)

Get the `n`th element of an iterable collection. Throw a `BoundsError`[@ref] if not existing.
Will advance any `Stateful`[@ref] iterator.

See also: [`first`](@ref), [`last`](@ref)

# Examples
```jldoctest
julia> Iterators.nth(2:2:10, 4)
8

julia> Iterators.nth(reshape(1:30, (5,6)), 6)
6

julia> stateful = Iterators.Stateful(1:10); Iterators.nth(stateful, 7)
7

julia> first(stateful)
8
```
"""
nth(itr, n::Integer) = _nth(IteratorSize(itr), itr, n)
nth(itr::Cycle{I}, n::Integer) where I = _nth(IteratorSize(I), itr, n)
nth(itr::Flatten{Take{Repeated{O}}}, n::Integer) where O = _nth(IteratorSize(O), itr, n)
@propagate_inbounds nth(itr::AbstractArray, n::Integer) = itr[begin + n - 1]

function _nth(::Union{HasShape, HasLength}, itr::Cycle{I}, n::Integer) where {I}
    N = length(itr.xs)
    N == 0 && throw(BoundsError(itr, n))