# Convert axes(a) etc to StepRange with a step other than 1

I want to loop over a matrix that might have custom indices. I can use `axes(a)` to get these. But I need a step size other than 1.

Is there a simple, generic way of converting Base.OneTo to a StepRange with a step other than 1 besides just doing it manually?

It would be good to have a helper method for this, I can’t imagine why else you would need to convert anything to a step range except to have a step size other than 1!

Something like this could convert `axes(a)` to StepRanges with a step size 2:

``````StepRange.(axes(a), 2)
``````

@Per has the better solution.

alternatively:

``````[first(x):3:last(x) for x in  axes(a)]
``````
2 Likes

It’s somehow unsatisfying to have to use a list comprehension for the most common reason for this conversion…

``````(x -> first(x):3:last(x)).(axes(a))
``````

This is likely more efficient, as it results in a tuple instead of an array.

1 Like
``````julia> StepRange.(first.(axes(a)),3,last.(axes(a)))
(1:3:7, 1:3:10, 1:3:13)

julia> function steprange(a::AbstractArray, stepby)
stops = axes(a)
return StepRange.(first.(stops), stepby, last.(stops))
end
steprange (generic function with 1 method)

julia> steprange(a, 3)
(1:3:7, 1:3:10, 1:3:13)
# ----

julia> a = fill(0, (8+1,12+1,16+1));axes(a)
(Base.OneTo(9), Base.OneTo(13), Base.OneTo(17))

julia> steps = (2,3,4)
(2, 3, 4)

julia> steprange(a, steps)
(1:2:9, 1:3:13, 1:4:17)

julia> collect.(ans)
([1, 3, 5, 7, 9], [1, 4, 7, 10, 13], [1, 5, 9, 13, 17])
``````
``````julia> Base.StepRange(first::T, step::T, last::AbstractRange) where {T<:Integer} =
StepRange(first, step, last.stop)

julia> StepRange(2, 5, Base.OneTo(17))
2:5:17

julia> collect(ans)
4-element Array{Int64,1}:
2
7
12
17
``````
1 Like

Yeah these are better! I imagine a lot faster as well without the allocation.

It would still be nice to have a method that accepted any other range and a step size…

Lets get that in base now

Edit: well a `StepRange(x, step)` constructor that accepted OneTo and the stepsize, anyway

I’d rather have a functon `restep(x, step) = first(x):step:last(x)` that would work on any range, not just `Base.OneTo`.

But with really small, rarely used functions like this, it is sometimes better to write out the code explicitly each time, rather than memorizing a function name and what it does.

Totally, that’s what I meant. But you would probably have to write a few specific implementations for OneTo and Range etc unless they just `convert()`. Edit: no you probably wouldn’t…

I also agree in principle that keeping rare function overhead down is a good idea. But in this case there are very few reasons to ever manually use `StepRange(x)` and at least a few of reasons to use `StepRange(x, step)`, so I’m not sure that really applies.

Yeah, this is what I love about Julia.

1 Like

Hah yeah I’m still not used to it! So much useless boilerplate to unlearn.