How to force mixed-type array of just ints and floats?

I’d like to store a table as a mixed-type numeric array - just ints and floats.

If I use [brackets] to initialize a vector of numeric values, Julia promotes the ints to floats and returns an array of floats. If I include a non-numeric type (e.g. string) as the last value and then pop! the vector (or subset it to a the index range of numeric-only values), it preserves the remaining numbers in an Any-type vector. Is there a way to do this without including then removing a non-numeric value?

v = [1.5,1,"foo"]; pop!(v); # v is now a length-2 Vector{Any} 
v = [1.5,1]; # v here is a Vector{Float64}

Apologies in advance if this has already been answered. I did do a search before posting.

You pre-pend the eltype:

Any[5,6]

gives an Array{Any,1}. To just store ints and floats you could do
Union{Int,Float64}[5, 6, 9.0] or maybe just Real[1, 2.0].

Edit: note that performance maybe worse with heterogeneous arrays.

4 Likes

Thanks for the quick answer, mauro3!

I wasn’t aware of the T[] syntax for arrays.

1 Like

Something to note: there’s a big jump in performance for functions acting on small union types between Julia 0.6 and 0.7, although operations on arrays of Reals don’t seem to have changed:

# v0.6.2
using BenchmarkTools
u = Union{Int64, Float64}[rand() < 0.5 ? 1 : 1.0 for i = 1:1000]
v =                  Real[rand() < 0.5 ? 1 : 1.0 for i = 1:1000]

@btime sum($u) # -> 42.516 μs (3466 allocations: 54.16 KiB)
@btime sum($v) # -> 27.661 μs (1000 allocations: 15.63 KiB)

vs.

# v0.7.0-DEV.5075
using BenchmarkTools
u = Union{Int64, Float64}[rand() < 0.5 ? 1 : 1.0 for i = 1:1000]
v =                  Real[rand() < 0.5 ? 1 : 1.0 for i = 1:1000]

@btime sum($u) # -> 9.788 μs (0 allocations: 0 bytes)
@btime sum($v) # -> 25.940 μs (999 allocations: 15.61 KiB)
3 Likes

Yep, Reals are not a small union, anything but as this post nicely describes: Type stability for returning abstract types - #2 by mbauman

1 Like