Julia 的一个核心目标是能够快速、高效地对数值数据进行计算。 _大量_的数值数据。
通常,这些数据会存储在数组(或某种相关类型)中,因此可以说,数组是 Julia 语言的核心。
数组的大小可以任意(只受硬件内存的限制),维数也可以任意多。
有些类型的数组有专门的名称(沿用自线性代数)。
一维数组称为 Vector,二维数组称为 Matrix。
在 Julia 中,两者都是 Array 的子类型。
这个入门概念专注于向量的基础知识。 更高维的数组会在教学大纲的后续部分介绍。
在 Julia 中,向量是一种有序的值序列,可以通过下标编号来访问。
创建向量最简单的方法,就是把值列在方括号里:
julia> num_vec = [1, 4, 9]
3-element Vector{Int64}:
1
4
9
julia> str_vec = ["arrays", "are", "important"]
3-element Vector{String}:
"arrays"
"are"
"important"
向量的类型与其中每个元素的类型相匹配。
严格来说,它是_列_向量,但如果你不熟悉线性代数,现在请先忽略这一点。 学完多维数组这个概念之后,就会更容易理解。
所以向量必须是同质的(所有元素类型都相同)?
从某种意义上说,是的,而且如果你想获得最佳性能,建议尽量朝这个方向努力。
不过,必要时 Julia 可以用Any类型绕过这个限制:
julia> mixed_vector = [1, "str", 'c']
3-element Vector{Any}:
1
"str"
'c': ASCII/Unicode U+0063 (category Ll: Letter, lowercase)
创建空向量时,Julia 默认的元素类型是Any,但可以通过给空数组标注所需的元素类型,来更具体地指定它。
julia> empty_vec = []
Any[]
julia> empty_int_vec = Int64[]
Int64[]
从全为 0 或全为 1 的向量开始是很常见的。为此,有(毫不意外地)名为zeros()和ones()的函数,它们把向量的大小作为形参。
默认类型是 Float64,但也可以选择指定其他数值类型。
由此延伸,fill()函数同时接收要重复的值和所需的向量大小。
julia> zeros(3)
3-element Vector{Float64}:
0.0
0.0
0.0
julia> ones(3)
3-element Vector{Float64}:
1.0
1.0
1.0
julia> ones(Int64, 3)
3-element Vector{Int64}:
1
1
1
julia> fill(42, 3)
3-element Vector{Int64}:
42
42
42
还有很多其他选项:参见手册。
请阅读并记住这条规则:
用过其他数据科学语言(R、Matlab、Fortran……)的人对此都很熟悉,但对有类 C 语言背景的计算机科学家来说,可能会觉得震惊。
除此之外,下标的工作方式和你猜的一样:把它们放进方括号里就行:
squares = [0, 1, 4, 9, 16]
squares[1] # 0
squares[3] # 4
squares[begin] # 0 ("begin" is synonym for 1)
squares[end] # 16 ("end" is synonym for length(squares))
注意用end(非常有用)和begin(大概没什么用)来索引有多方便。
Python 程序员可能会想用负下标。
别这么做:负下标不是 Julia 的一部分,用了会抛出BoundsError;任何小于 1 或大于length(squares)的下标也一样。
Julia 中的向量是_可变的_:我们可以修改单个元素的内容。
julia> vals = [1, 3, 5, 7]
4-element Vector{Int64}:
1
3
5
7
julia> vals[2] = 4 # reassign the value of this element
4
# Only the value at position 2 changes:
julia> vals
4-element Vector{Int64}:
1
4
5
7
有很多可用的函数可以用来操作向量,不过 Julia 文档把它们推广为“集合”,而不仅限于向量。
注意,按照惯例,会修改输入的函数,名字里都带!。
编译器不会强制这一点,但在 Julia 的世界里,这是一条非常_强_的惯例。
下面是几个有用的函数:
push!()。pop!()。pushfirst!()和popfirst!()。insert!()和deleteat!()。julia> vals = [1, 3]
2-element Vector{Int64}:
1
3
julia> push!(vals, 5, 6) # can add multiple values
4-element Vector{Int64}:
1
3
5
6
julia> pop!(vals) # mutates vals, return popped value
6
julia> vals
3-element Vector{Int64}:
1
3
5
向量的拼接相当简单,不过瞟一眼手册就会提醒你,涉及多维数组时,后面还藏着不少复杂之处。
append!()函数可以接收若干向量和单个元素的混合作为输入。
julia> append!([1, 2], [3, 4], [-1, -2], 15)
7-element Vector{Int64}:
1
2
3
4
-1
-2
15