Spiraling outwards iterator

Hey, I was looking for an iterator that spirals outward a given point. By that I stumbled over a Rosetta Code Challenge seeing that it is outdated (old iterator protocol) and that it goes inward clockwise. Thus it didn’t help. I’m telling here nevertheless because someone might want to challenge himself.

Now, using the algorithm from a StackOverflow question I came up with my own spiraling counter-clockward outwards iterator:

struct SpiralIterator
    center::CartesianIndex{2} #EDIT: {2} added according to suggestion of @jlperla 
end

function Base.iterate(iter::SpiralIterator, state=(0,0,-1,1))#x,y,d,m
    x, y, d, m = state
    2 * x * d < m && return (iter.center+CartesianIndex(x,y), (x+d, y, d, m))
    2 * y * d < m && return (iter.center+CartesianIndex(x,y), (x, y+d, d, m))
    return Base.iterate(iter, (x, y, -d, m+1))
end

Base.IteratorSize(::SpiralIterator) = Base.IsInfinite()

I wanted to ask if that’s idiomatic Julia and if you see anything to tweak (especially because the first condition is evaluated twice as often as the second one).

1 Like

I don’t think that center::CartesianIndex would lead to a concrete type in your structure. If not, you will need to make it parametric with center::T and T <: CartesianIndex or something along those lines

1 Like

What about CartesianIndex{2} as the algorithm only works for 2d anyway?

I think that is right. If it only works with {2} then you shouldn’t make it generic.

Note that a good way to check if things are concrete is:

julia> typeof(CartesianIndex)
UnionAll

julia> typeof(CartesianIndex{2})
DataType

The UnionAll means there are some parametric parameter, and hence will not be a concrete type if used in a struct. DataType means A-OK, and other things usually mean it is an abstract type.