I am trying to optimize this function to avoid using collect. My version uses vcat below:

""" Sums the cycle count given intervals of range_intervals and mean_intervals. The range_intervals and mean_intervals is given in fraction of range size"""
function sum_cycles(cycles::Vector{Cycle{T}}, range_intervals::Interval{T}, mean_intervals::Interval{T}) where {T <: Real}
bounds = find_boundary_vals(cycles)
bins = zeros(length(range_intervals)-1, length(mean_intervals)-1)
range_in = (range_intervals*bounds.max_range)/100
mean_in = (mean_intervals*(bounds.max_mean-bounds.min_mean))/100
mean_in = mean_in .+ bounds.min_mean
@assert issorted(mean_intervals) "The array needs to be sorted in raising order"
@assert issorted(range_intervals) "The array needs to be sorted in raising order"
mean_i = vcat(mean_in)
range_i = vcat(range_in)
#ensure the cycles is in the intervals by adding a small error to the end values of the interal.
error_m = (bounds.max_mean-bounds.min_mean) #instead of 1e-14 - The rounding is performed due to numerical noise in the floats when comparing
mean_i[end]+=error_m
mean_i[1]-=error_m
error_r = bounds.max_range #instead of 1e-14
range_i[end]+=error_r
range_i[1]-=error_r
@inbounds for cycle in cycles
i = find_range(range_i, cycle.range)
j = find_range(mean_i, cycle.mean)
bins[i,j] += cycle.count
end
return bins
end

Trying to see if I can make the code a bit prettier/faster, by extending the range slightly through a function.

May I ask why you keep the same step? That looks / reads strange to me mathematically and might explain your (strange) end points…

If you have 1:10 your step is 1.0, if you now try to use your function (let me take a more extreme δ) with δ=0.25
you would take as first point 0.75 but still steps of size 1, so you would not reach your desired end of 10.25 but only 9.75?

edit: You could keep the length (instead of keeping the step), then the step is adapted automatically, e.g.

julia> extend_range2(r,δ) = range(start=first(r)-δ, stop=last(r)+δ, length=length(r))
extend_range2 (generic function with 1 method)
julia> extend_range2(1:10, 0.25)
0.75:1.0555555555555556:10.25

Ranges compute the inclusive endpoints during construction, so if your step is too large, adjusting the likely exclusive input endpoint won’t make a difference

The intention is that the same sequence is represented by the same instance for comparison, even if the input values (3 of start, step, stop, or length) are different.

Adding eps(Float64) to 10 is actually doing nothing. You probably intended to add the smallest difference, but the thing about floating points is that difference depends on the absolute value. eps(Float64) does the difference for 1.0, and that is smaller than the difference for 10.0.