考虑这样一种情况,我首先使用eltype
为Any
逐步创建一个向量;之后,我想缩小其元素类型。我该如何做呢?
julia> vec = Any[1, 2, 3.]
3-element Vector{Any}:
1
2
3.0
我可以使用类似 convert(Vector{Real}, vec)
的方法。但在这种情况下,我手动指定了类型,而我希望让Julia自行决定最适合的eltype
。
考虑这样一种情况,我首先使用eltype
为Any
逐步创建一个向量;之后,我想缩小其元素类型。我该如何做呢?
julia> vec = Any[1, 2, 3.]
3-element Vector{Any}:
1
2
3.0
我可以使用类似 convert(Vector{Real}, vec)
的方法。但在这种情况下,我手动指定了类型,而我希望让Julia自行决定最适合的eltype
。
可以通过在给定容器(Array
或 Vector
)的每个元素上广播 identity
函数来实现:
julia> narrowed = identity.(vec)
3-element Vector{Real}:
1
2
3.0
julia> typeof(narrowed[1]), typeof(narrowed[3])
(Int64, Float64)
然而,在熟悉Julia相关函数的情况下,可以通过使用typejoin
函数详细地实现容器元素的类型合并。根据该函数的简明文档:
typejoin(T, S)
返回T和S的最近公共祖先,即它们都继承自的最窄类型。
typejoin
的参数应为Core.Type{T}
的子类型(但是,将其定义为typejoin(T...)
似乎更合理,因为它可以获得无限数量的位置参数,而不仅仅是两个)。
julia> typeof.(vec)
3-element Vector{DataType}:
Int64
Int64
Float64
julia> typejoin(typeof.(vec)...)
Real
julia> convert(Vector{typejoin(typeof.(vec)...)}, vec)
3-element Vector{Real}:
1
2
3.0
在Julia中,处理小型联合类型(例如Union{Int, Float64}
)比抽象类型更快,因此您应该避免使用抽象元素的向量,如Vector{Real}
,而是使用具体类型的联合类型,如Union{Int, Float64}
。
话虽如此,这里有一段代码可以生成这样的联合类型:
julia> Vector{Union{Set(typeof.(vec))...}}(vec)
3-element Vector{Union{Float64, Int64}}:
1
2
3.0
这里有一个简单的测试,表明对于一个100元素向量,性能差异为4倍:
julia> a1 = Vector{Union{Int, Float64}}(rand(100));
julia> a2 = Vector{Real}(rand(100));
julia> @btime minimum($a1);
428.643 ns (0 allocations: 0 bytes)
julia> @btime minimum($a2);
2.000 μs (102 allocations: 1.59 KiB)
promote
:
v = Any[1, 2, 3.0]
first.(promote.(v))
3-element Vector{Real}:
1
2
3.0000
v = Any[1, 2, 3.0, 3 + 2im]
first.(promote.(v))
4-element Vector{Number}:
1
2
3.0000
3 + 2im
但是,您可能更感兴趣的是获取元素的具体超类型向量,特别是出于性能考虑。因此,您可以使用以下内容:
v = Any[1, 2, 3.0]
reduce(vcat, promote(v...))
3-element Vector{Float64}:
1.0
2.0
3.0
v = Any[1, 2, 3.0, 3 + 2im]
reduce(vcat, promote(v...))
4-element Vector{ComplexF64}:
1.0 + 0.0im
2.0 + 0.0im
3.0 + 0.0im
3.0 + 2.0im
或者,简单点:
v = Any[1, 2, 3.0];
[v...]
3-element Vector{Float64}:
1.0
2.0
3.0
v = Any[1, 2, 3.0, 3+2im];
[v...]
4-element Vector{ComplexF64}:
1.0 + 0.0im
2.0 + 0.0im
3.0 + 0.0im
3.0 + 2.0im
[i for i in v]
。 - AboAmmar