Suppose I have an abstract type A, and a handful of concrete types B<:A , C<:A, etc.. What would be the appropriate way to specify a type Vector{ Union{ Vector{B}, Vector{C}, ...} } ? Vector{Vector{A}}, Vector{Vector{<:A}}, and Vector{<:Vector{A}} all allow the inner containers to take varied input (e.g., [B(), C()]), but I want to exclude these at minimum for performance reasons, and so only allow a situation like [ [B(), B()], [C(), C()] ]
julia> S = Vector{Union{Vector{Int}, Vector{Float64}}}()
Union{Vector{Float64}, Vector{Int64}}[]
julia> push!(S, [1,1,1])
1-element Vector{Union{Vector{Float64}, Vector{Int64}}}:
[1, 1, 1]
julia> push!(S, [1.,1.,1.])
2-element Vector{Union{Vector{Float64}, Vector{Int64}}}:
[1, 1, 1]
[1.0, 1.0, 1.0]
julia> push!(S, Union{Int, Float64}[1.,1.,1])
ERROR: MethodError: ...
@Syx Pek Yes exactly! Is there a way to specify the Union in the language of subtypes, so that I can instantiate more concrete types D<:A, E<:A, etc. and they slot in seamlessly?
julia> function insert_special(x::Vector{T}) where T <: Number
isconcretetype(T) || error("$T is not a concrete type")
push!(get!(S, T, Vector{T}[]), x)
end
insert_special (generic function with 1 method)
julia> S = Dict(Int => [[1,2,3], [4,5,6]], Float64 => [[1., 2., 3.]])
Dict{DataType, Vector} with 2 entries:
Float64 => [[1.0, 2.0, 3.0]]
Int64 => [[1, 2, 3], [4, 5, 6]]
julia> insert_special([1,2,3//2])
1-element Vector{Vector{Rational{Int64}}}:
[1//1, 2//1, 3//2]
julia> insert_special(Union{Int, Float64}[1,2,3.])
ERROR: Union{Float64, Int64} is not a concrete type
Stacktrace: ...
julia> for (_, val) in S, vec in val # Recovering the elements
println(vec)
end
[1.0, 2.0, 3.0]
[1, 2, 3]
[4, 5, 6]
Rational{Int64}[1//1, 2//1, 3//2]
This works if order doesn't matter. In general, we can allow the struct to be free, but check our vectors during insertion. (One doesn't need a dictionary here)
@Syx Pek awesome, that makes a ton of sense. Thank you!
Last updated: Nov 22 2024 at 04:41 UTC