How to convert Vector{Any} to a narrower type?

Consider the following Julia code

julia> a = Any[1, 2, 3.0]
3-element Vector{Any}:
 1
 2
 3.0

julia> map(x->x, a)
3-element Vector{Real}:
 1
 2
 3.0

Here I abused map to convert an array of Any to the narrowest type Real that all elements belong to. Is there a less hacky way to do this, while retaining the automatic detection of actual types inside the array?

1 Like

You can broadcast identity.

5 Likes

I just came across this and thought it’s worth benchmarking. Looks like map is better suited for this:

I had thought map might be the best approach, but I looked at the code it produces:

julia> @code_typed map(identity, a)
CodeInfo(
1 ─ %1 = %new(Generator{Vector{Any}, typeof(identity)}, identity, A)::Generator{Vector{Any}, typeof(identity)}
│   %2 = invoke Base._collect(A::Vector{Any}, %1::Generator{Vector{Any}, typeof(identity)}, $(QuoteNode(EltypeUnknown()))::EltypeUnknown, $(QuoteNode(HasShape{1}()))::HasShape{1})::Vector
└──      return %2
)=>Vector

Ok, so first it makes a generator, then collects it. So let’s try that:

julia> a = Any[1, 2, 3.0]
3-element Vector{Any}:
 1
 2
 3.0

julia> @btime identity.(a)
  1.815 μs (18 allocations: 720 bytes)
3-element Vector{Real}:
 1
 2
 3.0

julia> @btime map(identity, a)
  588.475 ns (8 allocations: 256 bytes)
3-element Vector{Real}:
 1
 2
 3.0

julia> @btime collect((x for x in $a))
  258.529 ns (6 allocations: 224 bytes)
3-element Vector{Real}:
 1
 2
 3.0

I’m not sure why this is so much faster. But it seems to work for arrays too, no problem:

julia> b = [a randn(3)]
3×2 Matrix{Any}:
 1     0.105208
 2    -1.05589
 3.0   0.310332

julia> collect((x for x in b))
3×2 Matrix{Real}:
 1     0.105208
 2    -1.05589
 3.0   0.310332
1 Like