强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

Julia 教程 / 数组与矩阵运算

数组与矩阵运算

1. 数组构造

字面量

# 一维数组(Vector)
v = [1, 2, 3, 4, 5]
typeof(v)    # Vector{Int64}(即 Array{Int64, 1})

# 二维数组(Matrix)
m = [1 2 3; 4 5 6]
# 2×3 Matrix{Int64}:
#  1  2  3
#  4  5  6

# 混合类型
mixed = [1, 2.0, "three"]
typeof(mixed)    # Vector{Any}

# 空数组
empty_int = Int[]        # 空的 Int64 数组
empty_float = Float64[]  # 空的 Float64 数组

构造函数

# 未初始化
A = Array{Float64}(undef, 3, 4)    # 3×4 未初始化矩阵

# 全零
Z = zeros(3, 3)                    # 3×3 Float64 零矩阵
Z = zeros(Int, 3, 3)               # 3×3 Int64 零矩阵

# 全一
O = ones(2, 3)                     # 2×3 Float64 全一矩阵

# 单位矩阵
I = Matrix{Float64}(I, 3, 3)       # 3×3 单位矩阵
# 或
using LinearAlgebra
I = I(3)                           # 3×3 UniformScaling

# 对角矩阵
D = Diagonal([1, 2, 3])

# 等间距向量
r = range(0, 1, length=11)         # 0.0:0.1:1.0
r = collect(0:0.1:1.0)             # 转为数组

# 随机数组
rand(3)               # 3 个 [0,1) 均匀分布随机数
randn(3, 3)           # 3×3 标准正态分布随机数
rand(1:10, 5)         # 5 个 [1,10] 随机整数
rand(['a','b','c'], 5) # 5 个随机字符

# 填充
fill(42, 3, 3)        # 3×3 全 42 矩阵
fill("x", 5)          # 5 个 "x"

2. 多维数组与 reshape

# 创建 1D 数组
v = collect(1:12)

# reshape 为 2D
m = reshape(v, 3, 4)
# 3×4 Matrix{Int64}:
#  1  4  7  10
#  2  5  8  11
#  3  6  9  12
# 注意:列优先(column-major)排列

# reshape 为 3D
t = reshape(v, 2, 3, 2)

# 使用 : 自动计算维度
reshape(v, 3, :)    # 3×4(自动计算第二维)

# 展平为 1D
vec(m)              # 12 元素向量

# 维度查询
ndims(m)            # 2
size(m)             # (3, 4)
size(m, 1)          # 3(行数)
size(m, 2)          # 4(列数)
length(m)           # 12

⚠️ 注意: Julia 使用列优先(column-major) 存储,与 MATLAB 相同,与 C/Python(行优先)不同。reshape 按列填充。


3. 数组索引

整数索引

A = [10 20 30; 40 50 60; 70 80 90]

A[1, 1]      # 10(行,列)
A[2, 3]      # 60
A[end, end]  # 90(最后一个元素)
A[end-1, :]  # [40, 50, 60](倒数第二行)

# 线性索引(按列展开)
A[1]         # 10
A[2]         # 40
A[5]         # 50

范围索引

A[1:2, :]       # 前两行
A[:, 2:3]       # 后两列
A[1:2, 1:2]     # 左上角 2×2 子矩阵
A[2:end, :]     # 第二行到最后一行

逻辑索引

A = [1, -2, 3, -4, 5]

# 布尔掩码
mask = A .> 0              # [true, false, true, false, true]
A[mask]                    # [1, 3, 5]

# 一步到位
A[A .> 0]                  # [1, 3, 5]
A[isodd.(A)]               # [1, 3, 5]

# 二维逻辑索引
M = [1 2; 3 4; 5 6]
M[M .> 3]                  # [5, 4, 6](按列展开)

笛卡尔索引

A = reshape(1:12, 3, 4)

# CartesianIndex
A[CartesianIndex(2, 3)]    # 8(第 2 行第 3 列)

# 用于 findmax/findmin
val, idx = findmax(A)
# val = 12, idx = CartesianIndex(3, 4)

4. 视图 vs 拷贝

A = [1 2 3; 4 5 6; 7 8 9]

# 切片返回拷贝(默认)
B = A[1:2, 1:2]
B[1, 1] = 999
A[1, 1]    # 仍然是 1(未被修改)

# 视图(共享内存)
V = @view A[1:2, 1:2]
V[1, 1] = 999
A[1, 1]    # 999(被修改了!)

# 等价写法
V = view(A, 1:2, 1:2)

# @views 宏(整块代码使用视图)
@views begin
    B = A[1:2, 1:2]    # 自动使用视图
    C = A[:, 1]         # 自动使用视图
end

💡 提示: @view 不分配新内存,性能更好。但持有视图会阻止原数组被垃圾回收。处理大数组时推荐使用视图。


5. 数组推导式

# 一维
squares = [x^2 for x in 1:10]

# 二维(生成矩阵)
M = [i + j for i in 1:3, j in 1:3]
# 3×3 Matrix{Int64}:
#  2  3  4
#  3  4  5
#  4  5  6

# 带过滤
evens = [x for x in 1:20 if iseven(x)]

# 嵌套推导式
coords = [(x, y) for x in 1:3 for y in 1:3]

# 生成器(惰性求值,不分配内存)
sum_of_squares = sum(x^2 for x in 1:1_000_000)

# 条件赋值
result = [isodd(x) ? x : x÷2 for x in 1:10]

6. 数组拼接

A = [1 2; 3 4]
B = [5 6; 7 8]

# 垂直拼接(行方向)
vcat(A, B)
# 4×2 Matrix{Int64}:
#  1  2
#  3  4
#  5  6
#  7  8

# 水平拼接(列方向)
hcat(A, B)
# 2×4 Matrix{Int64}:
#  1  2  5  6
#  3  4  7  8

# 语法糖
[A; B]       # vcat
[A B]        # hcat

# 沿任意维度拼接
cat(A, B, dims=1)    # 等价于 vcat
cat(A, B, dims=2)    # 等价于 hcat

# 三维拼接
cat(A, B, dims=3)    # 2×2×2 数组

# 矩阵与向量拼接
v = [9, 10]
hcat(A, v)           # 2×3 矩阵

7. 广播(Broadcasting)

广播是 Julia 最强大的数组操作之一,使用 . 语法:

# 标量与数组运算(自动广播)
A = [1, 2, 3, 4, 5]
A .+ 1         # [2, 3, 4, 5, 6]
A .* 2         # [2, 4, 6, 8, 10]
A .^ 2         # [1, 4, 9, 16, 25]

# 数组与数组广播
B = [10, 20, 30, 40, 50]
A .+ B         # [11, 22, 33, 44, 55]

# 函数广播
sqrt.(A)       # [1.0, 1.414, 1.732, 2.0, 2.236]
log.(A)        # [0.0, 0.693, 1.099, 1.386, 1.609]

# 二维广播
M = [1 2 3; 4 5 6]
M .+ [10, 20]      # 列广播(每列加不同的值)
M .+ [10 20 30]    # 行广播(每行加不同的值)

# 广播赋值
A = zeros(3, 3)
A .= sin.([1, 2, 3]) .* [1 2 3]    # 原地修改

# 广播与条件
x = [-2, -1, 0, 1, 2]
result = x .> 0 ? x : 0    # ERROR: 不行
result = ifelse.(x .> 0, x, 0)    # [0, 0, 0, 1, 2]

# 嵌套广播
f.(g.(x))    # 等价于
@. f(g(x))   # @. 宏自动给所有操作加点

💡 提示: @. 宏将表达式中所有操作都变为广播,非常方便:

x = [1.0, 2.0, 3.0]

# 手动加点
y = sqrt.(log.(abs.(x)) .+ 1)

# 使用 @.
y = @. sqrt(log(abs(x)) + 1)

8. Array{T,N} 类型参数

# T = 元素类型,N = 维度数
Array{Int64, 1}    # Vector{Int64}
Array{Float64, 2}  # Matrix{Float64}
Array{Any, 3}      # 3D Any 数组

# 类型别名
const Vector{T} = Array{T, 1}
const Matrix{T} = Array{T, 2}

# 类型层次
supertype(Vector{Int})    # AbstractVector{Int}
supertype(Matrix{Float64}) # AbstractMatrix{Float64}

# 类型参数约束
function typed_sum(v::Vector{T}) where T<:Number
    s = zero(T)
    for x in v
        s += x
    end
    return s
end

# 稀疏矩阵
using SparseArrays
S = sprand(1000, 1000, 0.01)    # 1000×1000,1% 非零
nnz(S)    # 非零元素数

9. 常用数组操作速查表

查询

函数说明
size(A)维度大小
length(A)元素总数
ndims(A)维度数
eltype(A)元素类型
isempty(A)是否为空
count(!iszero, A)非零元素数
findall(x -> x > 0, A)满足条件的索引
findfirst(isequal(3), A)第一个匹配的索引

变换

函数说明
copy(A)浅拷贝
deepcopy(A)深拷贝
reverse(A)反转
sort(A)排序
sort!(A)原地排序
permute!(A, p)按排列重排
circshift(A, n)循环移位
unique(A)去重
rotl90(A)逆时针旋转 90°
transpose(A)转置

归约

函数说明
sum(A)总和
prod(A)总积
maximum(A)最大值
minimum(A)最小值
extrema(A)(最小, 最大)
mean(A)均值(需要 using Statistics
std(A)标准差
cumsum(A)累积和
cumprod(A)累积积
diff(A)差分

多维归约

M = [1 2 3; 4 5 6]

sum(M, dims=1)      # 按列求和 → [5 7 9]
sum(M, dims=2)      # 按行求和 → [6; 15]
maximum(M, dims=1)  # 按列取最大 → [4 5 6]

# dropdims 去掉长度为 1 的维度
dropdims(sum(M, dims=1), dims=1)    # [5, 7, 9]

10. 矩阵运算

using LinearAlgebra

A = [1.0 2.0; 3.0 4.0]
B = [5.0 6.0; 7.0 8.0]

# 矩阵乘法
A * B            # 矩阵乘法
A \ b            # 求解 Ax = b
A / B            # A * inv(B)

# 转置
A'               # 共轭转置
transpose(A)     # 非共轭转置(实数矩阵相同)

# 逆矩阵
inv(A)

# 行列式
det(A)

# 特征值
eigen(A)

# 奇异值分解
svd(A)

# 秩
rank(A)

# 条件数
cond(A)

# 解线性方程组
b = [1.0, 2.0]
x = A \ b        # 求解 Ax = b(推荐,比 inv(A)*b 更快更稳定)

# LU 分解
lu(A)

# QR 分解
qr(A)

# Cholesky 分解(正定矩阵)
C = A * A'
cholesky(C)
运算函数说明
矩阵乘法A * B矩阵乘法
矩阵求逆inv(A)逆矩阵
线性求解A \ bAx=b 的解
行列式det(A)行列式
转置A'transpose(A)转置
特征分解eigen(A)特征值与特征向量
SVDsvd(A)奇异值分解
tr(A)主对角线和
rank(A)矩阵的秩
范数norm(A)Frobenius 范数
条件数cond(A)条件数

11. 业务场景:图像处理基础

using Statistics

# 模拟灰度图像(2D 数组)
img = rand(UInt8, 256, 256)

# 图像裁剪
cropped = img[50:150, 50:150]

# 亮度调整
brighter = clamp.(img .+ 50, 0, 255)

# 对比度调整
mean_val = mean(img)
adjusted = clamp.(round.(UInt8, mean_val .+ 1.5 .* (img .- mean_val)), 0, 255)

# 简单模糊(均值滤波 3×3)
function blur(img, k=3)
    h, w = size(img)
    result = similar(img)
    pad = k ÷ 2
    for i in 1:h, j in 1:w
        region = img[max(1,i-pad):min(h,i+pad), max(1,j-pad):min(w,j+pad)]
        result[i, j] = round(UInt8, mean(region))
    end
    return result
end

# 水平翻转
flipped_h = img[:, end:-1:1]

# 垂直翻转
flipped_v = img[end:-1:1, :]

# 旋转 90°
rotated = rotl90(img)

12. 性能优化提示

# ❌ 避免:循环中按索引赋值(会导致类型不稳定)
function bad_example(n)
    result = []
    for i in 1:n
        push!(result, i^2)
    end
    return result
end

# ✅ 推荐:预分配数组
function good_example(n)
    result = Vector{Int}(undef, n)
    for i in 1:n
        result[i] = i^2
    end
    return result
end

# ✅ 推荐:使用原地操作
A = rand(1000, 1000)
B = rand(1000, 1000)

# ❌ 每次分配新内存
C = A + B

# ✅ 原地修改
C = similar(A)
C .= A .+ B

# ✅ 使用 @views 避免拷贝
@views function compute(A)
    return sum(A[2:end-1, 2:end-1])
end

⚠️ 注意: Julia 数组是列优先(column-major) 存储。遍历二维数组时,外层循环应遍历列(第二维),内层循环遍历行(第一维),以获得最佳缓存命中率。

# ✅ 正确的遍历顺序(列优先)
function col_major_sum(A)
    s = zero(eltype(A))
    for j in 1:size(A, 2)       # 外层:列
        for i in 1:size(A, 1)   # 内层:行
            s += A[i, j]
        end
    end
    return s
end

扩展阅读


📌 本章小结: Julia 数组是列优先存储的同构容器。使用 zeros/ones/rand 构造,reshape 变换维度。索引支持整数、范围和布尔掩码。@view 创建零拷贝视图,广播使用 . 语法。LinearAlgebra 提供完整的矩阵运算支持。预分配和原地操作是关键性能优化手段。