How to break apart a UnitRange?

How would one break apart a UnitRange? From this example I’d like to create a Vector or Array that has 1,2,3,4,5,6 etc. in it, instead of 1:2, 3:4, 5:6

searching = DataFrame(A = 1:5:1000)
searching_specific = searching[:,:A]
inds = findall(isodd, searching_specific)
ranges = @views (:).(inds[1:end-1], inds[2:end] .- 1)

I think you are looking for collect():

julia> collect(1:6)
6-element Array{Int64,1}:
 1
 2
 3
 4
 5
 6

Thank you for your reply. collect() does not break apart the Vector{UnitRange{Int64}}. What I am using it for is more complicated - I have a DataFrame where I sort by 0, then take every 4th element in the Vector{UnitRange{Int64}}. I’d like to be able to ‘explode’ or break apart those sorted elements.

A = [1:2, 3:4, 5:6]
mapreduce(collect, vcat, A)
1 Like

you dont even need the map here

julia> A = [1:2, 3:4, 5:6]
3-element Array{UnitRange{Int64},1}:
 1:2
 3:4
 5:6

julia> reduce(vcat, A)
6-element Array{Int64,1}:
 1
 2
 3
 4
 5
 6
2 Likes

You can create your input data a lot more easily.

Instead you can write:

ranges = [i:i+1 for i in 1:2:197]

I’m just writing this to encourage you to simplify your questions more, by creating a minimal example. In particular, not everyone has DataFrames, and cannot understand your question without installing it. (In fact, you just put some data into a DataFrame and then read it directly back.)

I see I choose poorly for my MWE.

What I mean is, I do not want the middle values between each UnitRange. For example, if I have 1:252, 1225:1475, 2303:2555, 3342:3594, 4383:4652 in my UnitRange, I would like to break it apart into 1,252,1225,1475,2303 etc.

Hmm, this should work, though I don’t think it’s the most efficient way (it would be better to avoid creating the temporary arrays):

reduce(vcat, [first(x), last(x)] for x in ranges)

Thank you very much! I will use this for plotting.

If anyone needs more performance for this task, you can create a lazy datastructure first and (if absolutely necessary) collect it

range_limits(ranges) = Iterators.Flatten((first(r), last(r)) for r in ranges) |> collect

some benchmarks:

julia> using BenchmarkTools
julia> range_limits_allocating(ranges) = reduce(vcat, [first(x), last(x)] for x in ranges)
range_limits_allocating (generic function with 1 method)

julia> @benchmark range_limits_allocating($([rand(1:1000):rand(1:1000) for i in 1:100]))
BenchmarkTools.Trial: 
  memory estimate:  99.25 KiB
  allocs estimate:  199
  --------------
  minimum time:     8.237 μs (0.00% GC)
  median time:      9.432 μs (0.00% GC)
  mean time:        11.586 μs (10.10% GC)
  maximum time:     724.096 μs (98.04% GC)
  --------------
  samples:          10000
  evals/sample:     1

julia> @benchmark range_limits($([rand(1:1000):rand(1:1000) for i in 1:100]))
BenchmarkTools.Trial: 
  memory estimate:  4.38 KiB
  allocs estimate:  11
  --------------
  minimum time:     1.145 μs (0.00% GC)
  median time:      1.307 μs (0.00% GC)
  mean time:        1.521 μs (6.75% GC)
  maximum time:     148.801 μs (97.83% GC)
  --------------
  samples:          10000
  evals/sample:     10

so for 100 ranges this gives a roughly 10x speed up. without the collect it’s basically instantanous bc nothing is actually calculated

2 Likes

That’s clever! I didn’t realize that would work. But I wonder if it’s more idiomatic to use the function, ‘flatten’, rather than the (undocumented) constructor ‘Flatten’.

2 Likes

Oh, yeah! That definitely makes more sense. For some reason I thought Iterators.Flatten() was the documented method for that