【问题标题】:Julia: Initializing numeric arrays of different typesJulia:初始化不同类型的数值数组
【发布时间】:2020-11-09 17:34:08
【问题描述】:

我正在尝试在 Julia 中构建一个二元数组,其中每个子数组都有不同的类型(一个是 Int64s 的向量,另一个是 Float32s 的数组)。

下面的代码自动将我想要成为Int64 的元素转换为Float32,这是我不想要的:

my_multitype_array = [ collect(1:5), rand(Float32,3) ]

生成的数组会自动将第一个数组(通过collect(1:5) 定义)中的Int64s 转换为Float32,生成的my_multitype_array 的类型为2-element Array{Array{Float32,1}}。如何强制它使第一个子数组保持Int64s?在用值填充之前,我是否需要将 my_multitype_array 预定义为一个包含两个所需类型元素的空数组?

最后,一旦我确实拥有了不同类型的所需数组,在函数中预先声明其类型时,我将如何引用它?我的意思见下文:

function foo_function(first_scalar_arg::Float32, multiple_array_arg::Array{Array{Float32,1}})
       # do stuff
       return
end

我会写::Array{Array{Any,1}} 或其他什么,而不是::Array{Array{Float32,1}}

【问题讨论】:

  • 在您得到的答案中,您可以使用 Union 类型。但是您也可以考虑外部结构是否是元组而不是数组。这可能会更有效,因为它会在编译时知道两种内部类型。

标签: arrays types type-conversion julia variable-declaration


【解决方案1】:

如何实例化不同类型的向量:

如果你在终端中键入向量,它将被提升为最大的常用类型:

julia> [[1], [1.0]]
2-element Array{Array{Float64,1},1}:
 [1.0]
 [1.0]

原因是你没有指定外层向量的类型,所以 Julia 会尝试根据内容来推断类型。更具体的类型总是更有效,所以如果向量类型可以转换为可以表示所有内部向量的单一类型,这将完成(通过promote 机制)。为避免这种情况,您需要手动指定外部向量类型,例如:

julia> Any[[1], [1.0]]
2-element Array{Any,1}:
 [1]
 [1.0]

如何引用不同类型向量的向量

仔细想想,“不同类型向量的向量”不是单一类型,而是无限的类型集合。这些类型在 Julia 中称为“unionall 类型”,由 where 关键字表示。在这种情况下,您需要Vector{T} where T <: Vector

但是等等!那怎么来的:

julia> Any[[1], [1.0]] isa Vector{T} where T <: Vector
false

嗯,一个可以包含任何元素的向量并不是真正的向量的向量。所以在这里你有两个选择:

  • 要么通过删除类型注释或显着重新排列它们来放松你的函数签名(这是首选,因为你传入的值实际上可能是向量的向量,即使它的类型是 Vector{Any}):
function foo_function(first_scalar_arg, multiple_array_arg::AbstractArray)
       # do stuff
       return
end
  • 否则,请注意确保最初构建“向量的向量”:
julia> Vector[[1], [1.0]]
2-element Array{Array{T,1} where T,1}:
 [1]
 [1.0]

julia> Vector[[1], [1.0]] isa Vector{T} where T <: Vector
true

【讨论】:

  • 谢谢您-我接受了另一个答案,因为它是对我最初提出的问题的更直接和适当的答案,但就解释而言,您的回答实际上对我来说更合适/更有教育意义与这个问题相关的各种概念,所以非常感谢:)
【解决方案2】:

我认为以下代码更符合问题中的要求:

julia> a = Union{Array{Int},Array{Float64}}[[1,2,3],rand(2,2)]
2-element Array{Union{Array{Float64,N} where N, Array{Int64,N} where N},1}:
 [1, 2, 3]
 [0.834902264215698 0.42258382777543124; 0.5856562680004389 0.6654033155981287]

这将创建一个实际的数据结构,它知道它包含Float64Int 数组。

一些用法

julia> a[1]
3-element Array{Int64,1}:
 1
 2
 3

julia> a[2]
2×2 Array{Float64,2}:
 0.834902  0.422584
 0.585656  0.665403

以及操纵结构:

julia> push!(a, [1, 1]); #works

julia> push!(a, [true, false]);
ERROR: MethodError: no method matching Union{Array{Float64,N} where N, Array{Int64,N} where N}(::Array{Bool,1})

【讨论】:

  • 太好了,谢谢。关于问题的第二部分(在函数中注释类型),我是否会将参数的类型预先声明为arg::Array{Union{Array{Float64,N} where N, Array{Int64,N} where N},1}
  • 你不需要写where N,除非你在函数体中需要N的信息。因此,通常写arg::Vector{Union{Array{Float64}, Array{Int64}}} 就足够了。但是,如果您需要有关类型中数组大小的信息,那么它会变得复杂得多。例如,如果维度取决于您可以拥有的元素类型 function f(arg::Vector{Union{Array{Float64,N1}, Array{Int64,N2}}}) where {N1,N2}
【解决方案3】:

稍微扩展@Przemyslaw Szufel 的回答...

如您所见,使用混合类型的元素创建向量很棘手,因为字面量数组构造函数试图将元素提升为通用类型。有一种特殊的语法可以解决这个问题,手册 here 中对此进行了描述。

在您的情况下,您可以按如下方式构建向量向量:

julia> Union{Vector{Int64}, Vector{Float32}}[[1, 2], [1.0f0, 2.0f0]]
2-element Array{Union{Array{Float32,1}, Array{Int64,1}},1}:
 [1, 2]
 Float32[1.0, 2.0]

文字数组构造函数的前缀指定数组的元素类型。所以在这种情况下,向量的元素类型被限制为

Union{Vector{Int64}, Vector{Float32}}

也就是说,外层向量的元素必须是Int64的向量或者Float32的向量。

【讨论】:

  • 你写它的方式实际上比我的好,所以我更新了我的答案。当然(T where T&lt;:Union{Array{Int},Array{Float64}}) === Union{Array{Int},Array{Float64}}true,因此我过度使用了括号。
猜你喜欢
  • 2018-02-23
  • 2013-12-23
  • 1970-01-01
  • 1970-01-01
  • 2013-09-22
  • 2022-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多