Julia 数组
数组,就是相同数据类型的元素按一定顺序排列的集合,可以是一维数组和多维数组。
Julia 数组是可变类型集合,用于列表、向量、表格和矩阵。
Julia 数组的索引从 1 开始(不是 0),数组的大小不是固定的,可以动态增长。
Julia 数组用方括号 [...] 指定,多个元素使用逗号 , 分隔。创建一个一维数组(即一个向量)语法为:
[A, B, C, ...]
创建一维数组
下面实例创建了一个简单的一维数组:
实例
3-element Vector{Int64}:
1
2
3
上面的实例中我们创建了一个包含 3 个元素的一维数组,每个元素都是一个 64 位整数。
数组元素的类型也可以不一样,此时元素类型会是 Any:
实例
4-element Vector{Any}:
1
"RUNOOB"
2.5
π = 3.1415926535897...
注意:元素类型为 Any 的数组性能较差(每个元素都是指针,无法紧凑存储),实际开发中应尽量让数组元素类型一致,详见性能技巧章节。
当然也可以强制指定类型:
实例
3-element Vector{Int64}:
1
2
3
julia> arr2 = String["Taobao", "RUNOOB", "GOOGLE"]
3-element Vector{String}:
"Taobao"
"RUNOOB"
"GOOGLE"
我们也可以创建一个空数组:
实例
Int64[]
julia> arr2 = String[]
String[]
索引访问
创建的数组可以直接使用索引值来访问,第一个值的索引为 1(不是 0),最后一个可以使用 end 表示:
实例
julia> arr[2]
2
julia> arr[end]
3
# 范围索引取出子数组
julia> arr[1:2]
2-element Vector{Int64}:
1
2
指定数组类型及维度
我们还可以使用以下语法指定数组的类型和维度:
Array{type}(undef, dims...)
undef 表示数组未初始化。
dims... 可以是维度的元组,也可以是多个整数参数。
实例
3-element Vector{Int64}:
4834342704
4377305096
0
julia> array = Array{Int64}(undef, 3, 3, 3) # 3 维数组,每个维度 3 个元素
3×3×3 Array{Int64, 3}:
[:, :, 1] =
4562265712 0 0
...
undef 用于设置数组未初始化为任何已知值,这就是我们在输出中得到随机数的原因。未初始化的数组必须在赋值后才能安全读取。
创建二维数组和矩阵
我们可以将数组元素中的逗号省略掉或者使用两个分号 ;;,这样就可以创建一个二维数组了:
实例
1×4 Matrix{Int64}:
1 2 3 4
julia> [1;; 2;; 3;; 4]
1×4 Matrix{Int64}:
1 2 3 4
虽然只有一行,也是二维数组,因为 Julia 只认可列向量,而不认可所谓的行向量。
要添加另一行,只需添加分号 ;:
实例
2×2 Matrix{Int64}:
1 2
3 4
也可以使用冒号 : 和空格来实现:
实例
2×2 Matrix{Int64}:
1 3
2 4
我们也可以在方括号中嵌入多个长度相同的一维数组,并用空格分隔来创建二维数组:
实例
2×3 Matrix{Int64}:
1 3 5
2 4 6
julia> [[1 2]; [3 4]; [5 6]]
3×2 Matrix{Int64}:
1 2
3 4
5 6
拼接函数 hcat / vcat / cat
上面方括号里的空格与分号其实是 hcat(水平拼接)和 vcat(垂直拼接)的语法糖,更一般化的拼接用 cat 函数:
| 语法 | 等价函数 | 说明 |
|---|---|---|
[A; B; C] | vcat(A, B, C) | 沿第一维(垂直)拼接 |
[A B C] | hcat(A, B, C) | 沿第二维(水平)拼接 |
[A B; C D] | hvcat(A, B, C, D) | 同时垂直和水平拼接 |
cat(A, B; dims=k) | 沿第 k 维拼接,最通用 |
实例
4-element Vector{Int64}:
1
2
3
4
julia> hcat([1, 2], [3, 4])
2×2 Matrix{Int64}:
1 3
2 4
julia> cat([1 2], [3 4]; dims=3) # 沿第三维拼接成 3 维数组
2×2×2 Array{Int64, 3}:
[:, :, 1] =
1 2
...
使用范围函数来创建数组
省略号 ...
可以使用省略号 ... 来展开一个范围创建数组:
实例
11-element Vector{Int64}:
0
1
2
3
4
5
6
7
8
9
10
collect() 函数
collect() 函数语法格式如下:
collect(start:step:stop)
start 为开始值,step 为步长,stop 为结束值,该函数返回数组:
实例
7-element Vector{Int64}:
1
3
5
7
9
11
13
collect() 函数也可以指定元素类型:
实例
3-element Vector{Float64}:
1.0
3.0
5.0
range() 函数
range() 函数可以生成一个区间范围并指定步长,可以方便 collect() 函数调用:
实例
1:100
julia> range(1, stop=100)
1:100
julia> range(1, step=5, length=100)
1:5:496
julia> range(1, 10, length=101)
1.0:0.09:10.0
julia> range(start=1, step=1, stop=10)
1:1:10
如果未指定长度 length,且 stop - start 不是 step 的整数倍,则将生成在 stop 之前结束的范围:
julia> range(1, 3.5, step=2) 1.0:2.0:3.0
使用 range() 和 collect() 创建数组:
实例
10-element Vector{Int64}:
1
2
3
4
5
6
7
8
9
10
注意:range 返回的是惰性的 Range 对象而不是数组,它只存储起点、步长、长度三个数,不管区间多大都不占内存。大多数接受数组的地方也接受 Range,只有在确实需要数组时才 collect。
使用推导式和生成器创建数组
创建数组的另一种有用方法是使用推导式,语法格式如下:
A = [ F(x,y,...) for x=rx, y=ry, ... ]
实例
5-element Vector{Int64}:
1
4
9
16
25
# 双变量推导创建二维数组
julia> [n*m for n in 1:3, m in 1:3]
3×3 Matrix{Int64}:
1 2 3
2 4 6
3 6 9
也可以在没有方括号的情况下编写推导,从而产生称为生成器的对象:
实例
5-element Vector{Int64}:
1
4
9
16
25
# 生成器不分配中间数组,直接对序列求和
julia> sum(1/n^2 for n=1:1000)
1.6439345666815615
数组基本函数
| 函数 | 描述 |
|---|---|
eltype(A) | A 中元素的类型 |
length(A) | A 中元素的数量 |
ndims(A) | A 的维数 |
size(A) | 一个包含 A 各个维度上元素数量的元组 |
size(A, n) | A 第 n 维中的元素数量 |
axes(A) | 一个包含 A 有效索引的元组 |
eachindex(A) | 一个访问 A 中每一个位置的高效迭代器 |
stride(A, k) | 在第 k 维上相邻元素间的索引距离 |
实例
julia> size(A)
(2, 3)
julia> ndims(A)
2
julia> length(A)
6
julia> eltype(A)
Int64
构造和初始化函数
Julia 提供了许多用于构造和初始化数组的函数。大部分函数的第一个参数表示数组的元素类型 T,如果省略则默认为 Float64:
| 函数 | 描述 |
|---|---|
Array{T}(undef, dims...) | 一个没有初始化的密集 Array |
zeros(T, dims...) | 一个全零 Array |
ones(T, dims...) | 一个元素均为 1 的 Array |
trues(dims...) | 一个每个元素都为 true 的 BitArray |
falses(dims...) | 一个每个元素都为 false 的 BitArray |
reshape(A, dims...) | 一个包含跟 A 相同数据但维数不同的数组 |
copy(A) | 拷贝 A |
deepcopy(A) | 深拷贝,递归地拷贝其元素 |
similar(A, T, dims...) | 与 A 相同类型的未初始化数组,但具有指定的元素类型和维数 |
reinterpret(T, A) | 与 A 具有相同二进制数据的数组,但元素类型为 T |
rand(T, dims...) | 随机数组,元素均匀分布于 [0, 1) 区间(浮点类型) |
randn(T, dims...) | 随机数组,元素为标准正态分布 |
Matrix{T}(I, m, n) | m 行 n 列的单位矩阵(需要先 using LinearAlgebra) |
fill!(A, x) | 用值 x 填充数组 A(原地修改) |
fill(x, dims...) | 一个被值 x 填充的新 Array |
zeros() 创建数组的实例:
实例
2×3 Matrix{Int8}:
0 0 0
0 0 0
julia> zeros((2, 3)) # 不指定类型默认为 Float64
2×3 Matrix{Float64}:
0.0 0.0 0.0
0.0 0.0 0.0
添加、删除与修改元素
Julia 数组大小可变,最常用的增删函数都带感叹号后缀(表示原地修改):
| 函数 | 描述 |
|---|---|
push!(A, x) | 在数组末尾添加元素 x |
pop!(A) | 移除并返回数组末尾的元素 |
pushfirst!(A, x) | 在数组开头插入元素 x |
popfirst!(A) | 移除并返回数组开头的元素 |
append!(A, B) | 把集合 B 的所有元素追加到 A 末尾 |
insert!(A, i, x) | 在第 i 个位置插入元素 x |
deleteat!(A, i) | 删除第 i 个位置的元素 |
splice!(A, i) | 删除并返回第 i 个位置的元素 |
resize!(A, n) | 调整数组长度为 n |
empty!(A) | 清空数组 |
实例
julia> push!(arr, 1) # 末尾添加
1-element Vector{Int64}:
1
julia> append!(arr, [2, 3]) # 追加多个
3-element Vector{Int64}:
1
2
3
julia> pushfirst!(arr, 0) # 开头插入
4-element Vector{Int64}:
0
1
2
3
julia> pop!(arr) # 弹出末尾
3
julia> insert!(arr, 2, 99) # 第 2 个位置插入
4-element Vector{Int64}:
0
99
1
2
julia> deleteat!(arr, 2) # 删除第 2 个元素
3-element Vector{Int64}:
0
1
2
注意:不要用
arr = push!(arr, 1)这种写法(虽然结果正确),push! 已经原地修改了 arr,直接调用即可。也不要写arr = [arr; 1]来添加元素,它每次都会复制整个数组,性能差。
修改元素与广播
修改单个元素直接用索引赋值,批量修改用点赋值 .=:
实例
julia> A[1] = 100;
julia> A
3-element Vector{Int64}:
100
2
3
# .= 广播赋值:给所有元素加 10(原地修改,不新建数组)
julia> A .+= 10
3-element Vector{Int64}:
110
12
13
# 也可以对部分元素广播赋值
julia> A[1:2] .= 0
2-element view(::Vector{Int64}, 1:2) with eltype Int64:
0
0
broadcast(广播)机制可以把不同尺寸的数组或标量按元素组合起来,标量会自动"扩展":
实例
# 向量 a 逐列加到矩阵 A 上
julia> a .+ A
2×2 Matrix{Float64}:
2.0 3.0
5.0 6.0
# 任意函数都可以广播
julia> string.("item", 1:3)
3-element Vector{String}:
"item1"
"item2"
"item3"
性能提示:嵌套的点运算(如
2 .* A .+ B)会被融合成单次循环,不会产生临时数组,因此比2*A + B(产生两个临时数组)快得多,推荐优先使用点语法。
数组运算
数组支持的运算符:
| 类别 | 运算符 | 说明 |
|---|---|---|
| 一元算术 | -、+ | 逐元素取负等 |
| 二元算术 | - + * / \ ^ | * 是矩阵乘法,其余为线性代数运算 |
| 点运算 | .+ .* .- .^ | 逐元素运算 |
| 比较 | ==、.== | == 比较整个数组,.== 逐元素比较 |
实例
# * 是矩阵乘法
julia> A * B
2×2 Matrix{Int64}:
19 22
43 50
# .* 是逐元素乘法
julia> A .* B
2×2 Matrix{Int64}:
5 12
21 32
# == 比较整个数组是否相等,返回一个布尔值
julia> A == [1 2; 3 4]
true
# .== 逐元素比较,返回布尔数组
julia> A .== B
2×2 BitMatrix:
0 0
0 0
常用聚合函数
实例
julia> sum(A), prod(A)
(10, 24)
julia> maximum(A), minimum(A)
(4, 1)
julia> argmax(A), argmin(A) # 最大值/最小值的位置
(4, 1)
julia> mean(A) # 平均值需要 using Statistics
2.5
julia> sort([3, 1, 2])
3-element Vector{Int64}:
1
2
3
# 沿维度聚合,dims=1 表示按列求和
julia> sum([1 2; 3 4], dims=1)
1×2 Matrix{Int64}:
4 6
