How recompute the eltype of a vector in Julia

Viewed 222

Let's say I have a vector v = Any[1,2,3,4]

And I would like to recompute its eltype in such a way that typeof(v) = Vector{Int}

Is it possible to accomplish this without having to manually concatenate each of the elements in v?

3 Answers

You can't "retype" the existing v, just create a copy of it with the more concrete type1.

Conversion

Assuming you already (statically) know the result type, you have multiple options. Most readable (and IMO, idiomatic) would be

Vector{Int}(v)

which is almost equivalent to

convert(Vector{Int}, v)

except that the latter does not copy if the input types is already the target type. Alternatively:

convert.(Int, v)

which surely copies as well.

What to convert to

If you don't know what the "common type" would be, there are multiple options how to get one that matches. In general, typejoin can be used to find a least upper bound:

mapreduce(typeof, typejoin, v; init=Union{})

The result will most likely be abstract, e.g. Real for an array of Ints and Float64s. So, for numeric types, you might be better off with promote_type:

mapreduce(typeof, promote_type, v; init=Union{})  # or init=Number

This at least gives you Float64 for mixed Ints and Float64s.

But all of this is not really recommended, since it might be fragile, surprising, and is certainly not type stable.


1For certain combinations of types, with compatible binary form, reinterpret will work and return a view with a different type, but this is only possible for bits types, which Any is not. For converting Any[1,2,3] to Int[1,2,3] copying is fundamentally necessary because the two arrays have different layouts in memory: the former is an array of pointers to individually allocated integers objects, whereas the latter stores the Int values inline in contiguous memory.

If you don't know the output type, then consider using a comprehension

foo(v) = [x for x in v]

This is considerably faster on my computer than identity.(v):

julia> v = Any[1,2,3,4];

julia> @btime foo($v);
  153.018 ns (2 allocations: 128 bytes)

julia> @btime identity.($v);
  293.908 ns (5 allocations: 208 bytes)

julia> @btime foo(v) setup=(v=Any[rand(0:9) for _ in 1:1000]);
  1.331 μs (2 allocations: 7.95 KiB)

julia> @btime identity.(v) setup=(v=Any[rand(0:9) for _ in 1:1000]);
  25.498 μs (494 allocations: 15.67 KiB)

This is a quick and dirty trick that usually solves the problem

julia> v = Any[1,2,3,4]
4-element Array{Any,1}:
 1
 2
 3
 4

julia> identity.(v)
4-element Array{Int64,1}:
 1
 2
 3
 4
Related