The surprising results above are because length is not defined for the Flatten object returned by flatten, which means that the size of the result cannot be determined in advance. If I define:
Base.length(fl::Base.Iterators.Flatten{<:AbstractVector{<:UnitRange}}) = sum(length, fl.it)
Base.iteratorsize(::Base.Iterators.Flatten{<:AbstractVector{<:UnitRange}}) = Base.HasLength()
then the benchmark results for the flatten approach become
BenchmarkTools.Trial:
memory estimate: 61.00 MiB
allocs estimate: 5
--------------
minimum time: 21.147 ms (1.61% GC)
median time: 27.357 ms (20.71% GC)
mean time: 28.169 ms (22.88% GC)
maximum time: 90.278 ms (76.97% GC)
--------------
samples: 178
evals/sample: 1
Maybe a more general version of the methods above could make it into Base? We’re getting a lot of mileage out of this simple question.
(As an aside, how awesome is it that you can just tinker like this in Julia!)
Edit: Julia issue: https://github.com/JuliaLang/julia/issues/23431.