Julia:不同类型的数组
Julia: array of arrays with different types
这里是 Julia newbe,来自 python。
所以,我想在 Python 中构建我称之为列表的内容,由列表组成的列表组成。在我的例子中,它是一个 1000 长的列表,其元素是 3 个列表的列表。
到目前为止,我是这样做的:
BIG_LIST = collect(Array{Int64,1}[[],[],[]] for i in 1:1000)
当所有三个最内部的列表都由整数组成时,这符合我的目的。
现在我需要其中 2 个是整数,而第三个是 Float。
这可能吗?我该怎么做?
如果您还可以更好地解释如何正确初始化这些对象,那就太好了。我知道 collect 不是这里的最佳选择。
请注意,3 个内部列表的长度在 3 个中是相同的,但在处理过程中可能会有所不同。
首先,如果您知道中间列表总是有 3 个元素,那么您最好对这些元素使用 Tuple
types。元组可以独立指定其元素的类型。所以像这样的东西可能适合你的目的:
julia> l = [(Int64[], Int64[], Float64[]) for _ in 1:10]
10-element Array{Tuple{Array{Int64,1},Array{Int64,1},Array{Float64,1}},1}:
([], [], [])
([], [], [])
([], [], [])
([], [], [])
([], [], [])
([], [], [])
([], [], [])
([], [], [])
([], [], [])
([], [], [])
julia> push!(l[1][3], 5)
1-element Array{Float64,1}:
5.0
julia> l
10-element Array{Tuple{Array{Int64,1},Array{Int64,1},Array{Float64,1}},1}:
([], [], [5.0])
([], [], [])
([], [], [])
([], [], [])
([], [], [])
([], [], [])
([], [], [])
([], [], [])
([], [], [])
([], [], [])
此处需要注意的一些细节,您可能会感兴趣:
可以使用 T[]
构造空但类型化的列表,其中 T
是元素类型。
collect(f(i) for i in 1:n)
本质上相当于一个简单的理解(就像你在python中习惯的那样):[f(i) for i in 1:n]
。请注意,由于变量 i
在这里不起作用,您可以将其替换为 _
占位符,以便它更立即出现在 reader 中,您实际上是在创建类似对象的集合(但不相同,因为它们不共享相同的底层内存;修改一个不会影响其他)。
我不知道有什么更好的方法来初始化这样一个集合,我不认为在这里使用 collect
(或理解)不是一个坏主意。对于相同对象的集合,fill
提供了一个有用的快捷方式,但它不适用于此处,因为所有子列表都将被链接。
现在,如果所有内部子列表的长度都相同,您可能想要切换到稍微不同的数据结构:元组向量的向量:
julia> l2 = [Tuple{Int64,Int64,Float64}[] for _ in 1:10]
10-element Array{Array{Tuple{Int64,Int64,Float64},1},1}:
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
julia> push!(l2[2], (1,2,pi))
1-element Array{Tuple{Int64,Int64,Float64},1}:
(1, 2, 3.141592653589793)
julia> l2
10-element Array{Array{Tuple{Int64,Int64,Float64},1},1}:
[]
[(1, 2, 3.141592653589793)]
[]
[]
[]
[]
[]
[]
[]
[]
弗朗索瓦给了你一个很好的答案。我只是想提出另一种可能性。听起来您的数据具有相当复杂但具体的结构。例如,你的外部列表有 1000 个元素,而你的内部列表总是有 3 个列表...
有时在这些情况下,构建您自己的类型并编写几个访问器函数会更直观。这样您就不会最终做 mylist[3][2][6]
之类的事情而忘记哪个索引指的是数据的哪个维度。例如:
struct MyInnerType
field1::Vector{Int}
field2::Vector{Int}
field3::Vector{Float64}
end
struct MyOuterType
x::Vector{MyInnerType}
function MyOuterType(x::Vector{MyInnerType})
length(x) != 1000 && error("This vector should always have length of 1000")
new(x)
end
end
我在这里猜测,但也许像这样的访问器函数对,例如field3
:
get_field3(y::MyInnerType, i::Int)::Float64 = y.field3[i]
get_field3(z::MyOuterType, iouter::Int, iinner::Int)::Float64 = get_field3(z.x[iouter], iinner)
请记住,在 Julia 中使用您自己的类型不会降低性能。
另外一件事,为了清楚起见,我在上面的函数中包含了所有类型信息,但这实际上也不是获得最佳性能所必需的。
这里是 Julia newbe,来自 python。
所以,我想在 Python 中构建我称之为列表的内容,由列表组成的列表组成。在我的例子中,它是一个 1000 长的列表,其元素是 3 个列表的列表。
到目前为止,我是这样做的:
BIG_LIST = collect(Array{Int64,1}[[],[],[]] for i in 1:1000)
当所有三个最内部的列表都由整数组成时,这符合我的目的。 现在我需要其中 2 个是整数,而第三个是 Float。 这可能吗?我该怎么做?
如果您还可以更好地解释如何正确初始化这些对象,那就太好了。我知道 collect 不是这里的最佳选择。
请注意,3 个内部列表的长度在 3 个中是相同的,但在处理过程中可能会有所不同。
首先,如果您知道中间列表总是有 3 个元素,那么您最好对这些元素使用 Tuple
types。元组可以独立指定其元素的类型。所以像这样的东西可能适合你的目的:
julia> l = [(Int64[], Int64[], Float64[]) for _ in 1:10]
10-element Array{Tuple{Array{Int64,1},Array{Int64,1},Array{Float64,1}},1}:
([], [], [])
([], [], [])
([], [], [])
([], [], [])
([], [], [])
([], [], [])
([], [], [])
([], [], [])
([], [], [])
([], [], [])
julia> push!(l[1][3], 5)
1-element Array{Float64,1}:
5.0
julia> l
10-element Array{Tuple{Array{Int64,1},Array{Int64,1},Array{Float64,1}},1}:
([], [], [5.0])
([], [], [])
([], [], [])
([], [], [])
([], [], [])
([], [], [])
([], [], [])
([], [], [])
([], [], [])
([], [], [])
此处需要注意的一些细节,您可能会感兴趣:
可以使用
T[]
构造空但类型化的列表,其中T
是元素类型。collect(f(i) for i in 1:n)
本质上相当于一个简单的理解(就像你在python中习惯的那样):[f(i) for i in 1:n]
。请注意,由于变量i
在这里不起作用,您可以将其替换为_
占位符,以便它更立即出现在 reader 中,您实际上是在创建类似对象的集合(但不相同,因为它们不共享相同的底层内存;修改一个不会影响其他)。我不知道有什么更好的方法来初始化这样一个集合,我不认为在这里使用
collect
(或理解)不是一个坏主意。对于相同对象的集合,fill
提供了一个有用的快捷方式,但它不适用于此处,因为所有子列表都将被链接。
现在,如果所有内部子列表的长度都相同,您可能想要切换到稍微不同的数据结构:元组向量的向量:
julia> l2 = [Tuple{Int64,Int64,Float64}[] for _ in 1:10]
10-element Array{Array{Tuple{Int64,Int64,Float64},1},1}:
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
julia> push!(l2[2], (1,2,pi))
1-element Array{Tuple{Int64,Int64,Float64},1}:
(1, 2, 3.141592653589793)
julia> l2
10-element Array{Array{Tuple{Int64,Int64,Float64},1},1}:
[]
[(1, 2, 3.141592653589793)]
[]
[]
[]
[]
[]
[]
[]
[]
弗朗索瓦给了你一个很好的答案。我只是想提出另一种可能性。听起来您的数据具有相当复杂但具体的结构。例如,你的外部列表有 1000 个元素,而你的内部列表总是有 3 个列表...
有时在这些情况下,构建您自己的类型并编写几个访问器函数会更直观。这样您就不会最终做 mylist[3][2][6]
之类的事情而忘记哪个索引指的是数据的哪个维度。例如:
struct MyInnerType
field1::Vector{Int}
field2::Vector{Int}
field3::Vector{Float64}
end
struct MyOuterType
x::Vector{MyInnerType}
function MyOuterType(x::Vector{MyInnerType})
length(x) != 1000 && error("This vector should always have length of 1000")
new(x)
end
end
我在这里猜测,但也许像这样的访问器函数对,例如field3
:
get_field3(y::MyInnerType, i::Int)::Float64 = y.field3[i]
get_field3(z::MyOuterType, iouter::Int, iinner::Int)::Float64 = get_field3(z.x[iouter], iinner)
请记住,在 Julia 中使用您自己的类型不会降低性能。
另外一件事,为了清楚起见,我在上面的函数中包含了所有类型信息,但这实际上也不是获得最佳性能所必需的。